Skip to content

Commit

Permalink
openv: use new pipieline
Browse files Browse the repository at this point in the history
  • Loading branch information
koush committed Mar 29, 2023
1 parent a20cc5c commit 8b46f0a
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 87 deletions.
4 changes: 2 additions & 2 deletions plugins/opencv/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion plugins/opencv/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@
"devDependencies": {
"@scrypted/sdk": "file:../../sdk"
},
"version": "0.0.70"
"version": "0.0.72"
}
115 changes: 37 additions & 78 deletions plugins/opencv/src/opencv/__init__.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
from __future__ import annotations
from time import sleep
from detect import DetectionSession, DetectPlugin

from typing import Any, List, Tuple
import numpy as np
import asyncio

import cv2
import imutils
Gst = None
try:
from gi.repository import Gst
except:
pass
from scrypted_sdk.types import ObjectDetectionModel, ObjectDetectionResult, ObjectsDetected, Setting, VideoFrame
from PIL import Image

class OpenCVDetectionSession(DetectionSession):
import numpy as np

from detect import DetectPlugin

import scrypted_sdk
from scrypted_sdk.types import (ObjectDetectionGeneratorSession,
ObjectDetectionResult,
ObjectsDetected, Setting, VideoFrame)


class OpenCVDetectionSession:
def __init__(self) -> None:
super().__init__()
self.cap: cv2.VideoCapture = None
self.previous_frame: Any = None
self.curFrame = None
Expand Down Expand Up @@ -110,8 +109,7 @@ def parse_settings(self, settings: Any):
blur = int(settings.get('blur', blur))
return area, threshold, interval, blur

def detect(self, detection_session: OpenCVDetectionSession, frame, src_size, convert_to_src_size) -> ObjectsDetected:
settings = detection_session.settings
def detect(self, frame, settings: Any, detection_session: OpenCVDetectionSession, src_size, convert_to_src_size) -> ObjectsDetected:
area, threshold, interval, blur = self.parse_settings(settings)

# see get_detection_input_size on undocumented size requirements for GRAY8
Expand Down Expand Up @@ -154,8 +152,8 @@ def detect(self, detection_session: OpenCVDetectionSession, frame, src_size, con
# if w * h != contour_area:
# print("mismatch w/h", contour_area - w * h)

x2, y2, _ = convert_to_src_size((x + w, y + h))
x, y, _ = convert_to_src_size((x, y))
x2, y2 = convert_to_src_size((x + w, y + h))
x, y = convert_to_src_size((x, y))
w = x2 - x + 1
h = y2 - y + 1

Expand Down Expand Up @@ -206,11 +204,24 @@ def end_session(self, detection_session: OpenCVDetectionSession):
detection_session.cap = None
return super().end_session(detection_session)

async def run_detection_image(self, detection_session: DetectionSession, image: Image.Image, settings: Any, src_size, convert_to_src_size) -> Tuple[ObjectsDetected, Any]:
# todo
raise Exception('can not run motion detection on image')

async def run_detection_videoframe(self, videoFrame: VideoFrame, detection_session: OpenCVDetectionSession) -> ObjectsDetected:
async def generateObjectDetections(self, videoFrames: Any, session: ObjectDetectionGeneratorSession = None) -> Any:
try:
ds = OpenCVDetectionSession()
videoFrames = await scrypted_sdk.sdk.connectRPCObject(videoFrames)
async for videoFrame in videoFrames:
detected = await self.run_detection_videoframe(videoFrame, session and session.get('settings'), ds)
yield {
'__json_copy_serialize_children': True,
'detected': detected,
'videoFrame': videoFrame,
}
finally:
try:
await videoFrames.aclose()
except:
pass

async def run_detection_videoframe(self, videoFrame: VideoFrame, settings: Any, detection_session: OpenCVDetectionSession) -> ObjectsDetected:
width = videoFrame.width
height = videoFrame.height

Expand Down Expand Up @@ -238,60 +249,8 @@ async def run_detection_videoframe(self, videoFrame: VideoFrame, detection_sessi
'resize': resize,
})

def convert_to_src_size(point, normalize = False):
return point[0] * scale, point[1] * scale, True
def convert_to_src_size(point):
return point[0] * scale, point[1] * scale
mat = np.ndarray((height, width, self.pixelFormatChannelCount), buffer=buffer, dtype=np.uint8)
detections = self.detect(
detection_session, mat, (width, height), convert_to_src_size)
detections = self.detect(mat, settings, detection_session, (width, height), convert_to_src_size)
return detections

async def run_detection_avframe(self, detection_session: DetectionSession, avframe, settings: Any, src_size, convert_to_src_size) -> Tuple[ObjectsDetected, Any]:
if avframe.format.name != 'yuv420p' and avframe.format.name != 'yuvj420p':
mat = avframe.to_ndarray(format='gray8')
else:
mat = np.ndarray((avframe.height, avframe.width, self.pixelFormatChannelCount), buffer=avframe.planes[0], dtype=np.uint8)
detections = self.detect(
detection_session, mat, src_size, convert_to_src_size)
if not detections or not len(detections['detections']):
await self.detection_sleep(settings)
return None, None
return detections, None

async def run_detection_gstsample(self, detection_session: OpenCVDetectionSession, gst_sample, settings: Any, src_size, convert_to_src_size) -> ObjectsDetected:
buf = gst_sample.get_buffer()
caps = gst_sample.get_caps()
# can't trust the width value, compute the stride
height = caps.get_structure(0).get_value('height')
width = caps.get_structure(0).get_value('width')
result, info = buf.map(Gst.MapFlags.READ)
if not result:
return None, None
try:
mat = np.ndarray(
(height,
width,
self.pixelFormatChannelCount),
buffer=info.data,
dtype=np.uint8)
detections = self.detect(
detection_session, mat, src_size, convert_to_src_size)
# no point in triggering empty events.
finally:
buf.unmap(info)

if not detections or not len(detections['detections']):
await self.detection_sleep(settings)
return None, None
return detections, None

def create_detection_session(self):
return OpenCVDetectionSession()

async def detection_sleep(self, settings: Any):
area, threshold, interval, blur = self.parse_settings(settings)
# it is safe to block here because gstreamer creates a queue thread
await asyncio.sleep(interval / 1000)

async def detection_event_notified(self, settings: Any):
await self.detection_sleep(settings)
return await super().detection_event_notified(settings)
1 change: 0 additions & 1 deletion plugins/opencv/src/pipeline

This file was deleted.

6 changes: 1 addition & 5 deletions plugins/opencv/src/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ numpy>=1.16.2
# pillow for anything not intel linux
Pillow>=5.4.1; sys_platform != 'linux' or platform_machine != 'x86_64'
pillow-simd; sys_platform == 'linux' and platform_machine == 'x86_64'
PyGObject>=3.30.4; sys_platform != 'win32'
imutils>=0.5.0
# not available on armhf
av>=10.0.0; sys_platform != 'linux' or platform_machine == 'x86_64' or platform_machine == 'aarch64'
# not available on armhf
opencv-python; sys_platform != 'linux' or platform_machine == 'x86_64' or platform_machine == 'aarch64'

opencv-python; sys_platform != 'linux' or platform_machine == 'x86_64'

0 comments on commit 8b46f0a

Please sign in to comment.