Table of contents
- feature detection
- Setup 1: Create the file
- Setup 2: Install dependencies
- Setup 3: Import required packages
- Setup 4: Create the pipeline
- Setup 5: Create Nodes
- Setup 6: Set related properties
- Setup 7: Establish link relationship
- Setup 8: Connect the device and start the pipeline
- Setup 9: Create input queue and output queue to communicate with DepthAI device
- Setup 10: Define `drawFeatures` function for drawing feature points on the image frame
- Setup 11: Main loop
- Setup 12: Run the program
feature detection
Feature detection refers to automatically finding and locating image regions or image points with specific features in digital images. These features can be objects, edges, corners, textures, etc. that have unique appearance, structure, or statistical properties in the image.
Feature detection plays a vital role in computer vision, and it is the basis of many computer vision tasks, such as object detection, tracking, pose estimation, image stitching, image recognition, etc. By extracting and matching features, computer vision tasks such as image alignment, object recognition, and motion estimation can be achieved.
Traditional feature detection methods include edge detection (such as Canny edge detection), corner detection (such as Harris corner detection), scale invariant feature transform (SIFT), accelerated robust feature (SURF), etc. In recent years, feature detection methods based on deep learning, such as convolutional neural network (CNN) feature extraction, have also made important breakthroughs and applications in the field of image feature detection.
Setup 1: Create the file
- Create a new 6-feature-detector folder
- Open the folder with vscode
- Create a new main.py file
Setup 2: Install dependencies
Before installing dependencies, you need to create and activate a virtual environment. I have created a virtual environment OAKenv here, enter cd in the terminal... to return to the root directory of OAKenv, and enter to activate the virtual OAKenv\Scripts\activate
environment
Install pip dependencies:
pip install numpy opencv-python depthai blobconverter --user
Setup 3: Import required packages
Import the packages required by the project in main.py
import cv2
import depthai as dai
Setup 4: Create the pipeline
pipeline = dai.Pipeline()
Setup 5: Create Nodes
Create a camera node
monoLeft = pipeline.createMonoCamera()
monoRight = pipeline.createMonoCamera()
monoLeft = pipeline.createMonoCamera()
: Create a single-channel camera node (MonoCamera) for capturing the left monochrome image.monoRight = pipeline.createMonoCamera()
: Create a single-channel camera node (MonoCamera) for capturing the monochrome image on the right.
Create a feature detection node
featureTrackerLeft = pipeline.createFeatureTracker()
featureTrackerRight = pipeline.createFeatureTracker()
This code creates three edge detection nodes in the pipeline.
featureTrackerLeft = pipeline.createFeatureTracker()
: Created a feature detection node to process the left monochrome image.featureTrackerRight = pipeline.createFeatureTracker()
: Created a feature detection node to process the monochrome image on the right.
Create a node for data interaction
xoutPassthroughFrameLeft = pipeline.createXLinkOut()
xoutTrackedFeaturesLeft = pipeline.createXLinkOut()
xoutPassthroughFrameRight = pipeline.createXLinkOut()
xoutTrackedFeaturesRight = pipeline.createXLinkOut()
xinTrackedFeaturesConfig = pipeline.createXLinkIn()
xoutPassthroughFrameLeft.setStreamName("passthroughFrameLeft")
xoutTrackedFeaturesLeft.setStreamName("trackedFeaturesLeft")
xoutPassthroughFrameRight.setStreamName("passthroughFrameRight")
xoutTrackedFeaturesRight.setStreamName("trackedFeaturesRight")
xinTrackedFeaturesConfig.setStreamName("trackedFeaturesConfig")
This code creates five nodes for data interaction with external devices.
- Using
pipeline.createXLinkOut()
the method creates four nodes for data output with external devices. - The usage
pipeline.createXLinkIn()
method creates a node for data input with an external device.
A dataflow name is set for each output node and input node
Use .setStreamName("name")
the method to set the dataflow name for the five nodes created above
Setup 6: Set related properties
Set the relevant properties of the camera
monoLeft.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P)
monoLeft.setBoardSocket(dai.CameraBoardSocket.LEFT)
monoRight.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P)
monoRight.setBoardSocket(dai.CameraBoardSocket.RIGHT)
For the monocular camera on the left:
monoLeft.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P)
: Set the resolution of the left monocular camera to 400P. This means that the left monocular camera will capture images at 400P resolution.monoLeft.setBoardSocket(dai.CameraBoardSocket.LEFT)
: Set the onboard slot of the left monocular camera to LEFT. This indicates that the left monocular camera will be connected via the left connector on the system board.
For the monocular camera on the right:
monoRight.setResolution(dai.MonoCameraProperties.SensorResolution.THE_400_P)
: Set the resolution of the right monocular camera to 400P. This means that the right monocular camera will capture images at 400P resolution.monoRight.setBoardSocket(dai.CameraBoardSocket.RIGHT)
: Set the onboard slot of the right monocular camera to RIGHT. This indicates that the right monocular camera will be connected via the right connector on the system board.
Set up the initial configuration of the feature detector
featureTrackerLeft.initialConfig.setMotionEstimator(False)
featureTrackerRight.initialConfig.setMotionEstimator(False)
Disables the motion estimator in a feature tracker instance.
For each feature tracker instance, initialConfig
is its initialization configuration object, which can be used to set different parameters.
Disable the motion estimator by calling setMotionEstimator(False)
the function and passing it as an argument. False
This means that the feature tracker will not estimate the motion between objects or feature points, but only track their positions.
Setup 7: Establish link relationship
Establish data connection between camera and feature tracker
monoLeft.out.link(featureTrackerLeft.inputImage)
featureTrackerLeft.passthroughInputImage.link(xoutPassthroughFrameLeft.input)
featureTrackerLeft.outputFeatures.link(xoutTrackedFeaturesLeft.input)
xinTrackedFeaturesConfig.out.link(featureTrackerLeft.inputConfig)
monoRight.out.link(featureTrackerRight.inputImage)
featureTrackerRight.passthroughInputImage.link(xoutPassthroughFrameRight.input)
featureTrackerRight.outputFeatures.link(xoutTrackedFeaturesRight.input)
xinTrackedFeaturesConfig.out.link(featureTrackerRight.inputConfig)
featureTrackerConfig = featureTrackerRight.initialConfig.get()
print("Press 's' to switch between Harris and Shi-Thomasi corner detector!")
monoLeft.out.link(featureTrackerLeft.inputImage)
: Link the output of the left monocular camera to the input image of the left feature tracker.featureTrackerLeft.passthroughInputImage.link(xoutPassthroughFrameLeft.input)
: Links the input image of the left feature tracker to the left frame output (used to pass the original input image to the output pipeline).featureTrackerLeft.outputFeatures.link(xoutTrackedFeaturesLeft.input)
: Links the output feature of the left feature tracker to the output of the left tracked feature.xinTrackedFeaturesConfig.out.link(featureTrackerLeft.inputConfig)
: Links the configuration of the tracked feature to the input configuration of the left feature tracker.monoRight.out.link(featureTrackerRight.inputImage)
: Link the output of the right monocular camera to the input image of the right feature tracker.featureTrackerRight.passthroughInputImage.link(xoutPassthroughFrameRight.input)
: Links the input image of the right feature tracker to the right frame output.featureTrackerRight.outputFeatures.link(xoutTrackedFeaturesRight.input)
: Links the output feature of the right feature tracker to the output of the right tracked feature.xinTrackedFeaturesConfig.out.link(featureTrackerRight.inputConfig)
: Links the configuration of the tracked feature to the input configuration of the feature tracker on the right.featureTrackerRight.initialConfig.get()
: Used to getfeatureTrackerRight
the initial configuration of the feature tracker instance.
This code snippet is mainly used to create a data pipeline that passes image data from the camera to the feature tracker and outputs the tracked features to the corresponding targets.
Setup 8: Connect the device and start the pipeline
with dai.Device(pipeline) as device:
Setup 9: Create input queue and output queue to communicate with DepthAI device
passthroughImageLeftQueue = device.getOutputQueue("passthroughFrameLeft", 8, False)
outputFeaturesLeftQueue = device.getOutputQueue("trackedFeaturesLeft", 8, False)
passthroughImageRightQueue = device.getOutputQueue("passthroughFrameRight", 8, False)
outputFeaturesRightQueue = device.getOutputQueue("trackedFeaturesRight", 8, False)
inputFeatureTrackerConfigQueue = device.getInputQueue("trackedFeaturesConfig")
leftWindowName = "left"
rightWindowName = "right"
passthroughImageLeftQueue = device.getOutputQueue("passthroughFrameLeft", 8, False)
: Get the output queue named "passthroughFrameLeft" from the device. This queue will be used to receive the frame image data of the left feature tracker, the queue size is 8, and no blocking mode is used.outputFeaturesLeftQueue = device.getOutputQueue("trackedFeaturesLeft", 8, False)
: Get an output queue named "trackedFeaturesLeft" from the device. This queue will be used to receive the tracking feature data of the left feature tracker, the queue size is 8, and the blocking mode is not used.passthroughImageRightQueue = device.getOutputQueue("passthroughFrameRight", 8, False)
: Get the output queue named "passthroughFrameRight" from the device. This queue will be used to receive the frame image data of the feature tracker on the right, the queue size is 8, and no blocking mode is used.outputFeaturesRightQueue = device.getOutputQueue("trackedFeaturesRight", 8, False)
: Get an output queue named "trackedFeaturesRight" from the device. This queue will be used to receive the tracking feature data of the feature tracker on the right, the queue size is 8, and the blocking mode is not used.inputFeatureTrackerConfigQueue = device.getInputQueue("trackedFeaturesConfig")
: Get an input queue named "trackedFeaturesConfig" from the device. This queue will be used to send configuration data to the feature tracker.
Setup 10: Defined drawFeatures
functions for drawing feature points on the image frame
def drawFeatures(frame, features):
pointColor = (0, 0, 255)
circleRadius = 2
for feature in features:
cv2.circle(frame, (int(feature.position.x), int(feature.position.y)), circleRadius, pointColor, -1, cv2.LINE_AA, 0)
defines a drawFeatures
function named , which is used to draw feature points on an image frame.
-
pointColor = (0, 0, 255)
: Defines the color used when drawing feature points. Here red in the RGB color space is used. -
circleRadius = 2
: Defines the radius of the circle used when drawing feature points. -
for feature in features:
: Loop through each feature in the feature list. -
cv2.circle(frame, (int(feature.position.x), int(feature.position.y)), circleRadius, pointColor, -1, cv2.LINE_AA, 0)
: Use the function of OpenCV to draw a circle oncv2.circle
the image frame .frame
The position of the center of the circle is determined by the position of the feature(feature.position.x, feature.position.y)
, the radius of the circlecircleRadius
is , the color ispointColor
, the line width is -1 to fill the entire circle,cv2.LINE_AA
specifying the use of anti-aliased line segments, and the last parameter is 0 to draw in the default image coordinate system.
Setup 11: Main loop
while True:
Get frame data and convert it to color
inPassthroughFrameLeft = passthroughImageLeftQueue.get()
passthroughFrameLeft = inPassthroughFrameLeft.getFrame()
leftFrame = cv2.cvtColor(passthroughFrameLeft, cv2.COLOR_GRAY2BGR)
inPassthroughFrameRight = passthroughImageRightQueue.get()
passthroughFrameRight = inPassthroughFrameRight.getFrame()
rightFrame = cv2.cvtColor(passthroughFrameRight, cv2.COLOR_GRAY2BGR)
-
inPassthroughFrameLeft = passthroughImageLeftQueue.get()
passthroughImageLeftQueue
: Get a frame from the named queue. -
passthroughFrameLeft = inPassthroughFrameLeft.getFrame()
inPassthroughFrameLeft
: Extract frame data from the obtained frame object . -
leftFrame = cv2.cvtColor(passthroughFrameLeft, cv2.COLOR_GRAY2BGR)
cv2.cvtColor
: Convert a grayscale imagepassthroughFrameLeft
to a color image using OpenCV's functions. The color conversion code used herecv2.COLOR_GRAY2BGR
converts a grayscale image to a BGR color image. -
inPassthroughFrameRight = passthroughImageRightQueue.get()
passthroughImageRightQueue
: Get another frame from the named queue. -
passthroughFrameRight = inPassthroughFrameRight.getFrame()
inPassthroughFrameRight
: Extract frame data from the obtained frame object . -
rightFrame = cv2.cvtColor(passthroughFrameRight, cv2.COLOR_GRAY2BGR)
cv2.cvtColor
: Convert a grayscale imagepassthroughFrameRight
to a color image using OpenCV's functions. The color conversion code used herecv2.COLOR_GRAY2BGR
converts a grayscale image to a BGR color image.
Get the tracked features and draw those features on the frame
trackedFeaturesLeft = outputFeaturesLeftQueue.get().trackedFeatures
drawFeatures(leftFrame, trackedFeaturesLeft)
trackedFeaturesRight = outputFeaturesRightQueue.get().trackedFeatures
drawFeatures(rightFrame, trackedFeaturesRight)
This code takes the tracked features from the output feature queue and draws them on the frame.
-
trackedFeaturesLeft = outputFeaturesLeftQueue.get().trackedFeatures
:outputFeaturesLeftQueue
Get a feature tracking result object from the output feature queue named and extract the tracked features from it. -
drawFeatures(leftFrame, trackedFeaturesLeft)
: CalldrawFeatures
the function named and pass in the left frameleftFrame
and tracked left featurestrackedFeaturesLeft
as parameters to draw feature points on the left frame. -
trackedFeaturesRight = outputFeaturesRightQueue.get().trackedFeatures
:outputFeaturesRightQueue
Get another feature tracking result object from the output feature queue named , and extract the tracked features from it. -
drawFeatures(rightFrame, trackedFeaturesRight)
: CalldrawFeatures
the function named and pass in the right framerightFrame
and tracked right featurestrackedFeaturesRight
as parameters to draw feature points on the right frame.
display frame image
cv2.imshow(leftWindowName, leftFrame)
cv2.imshow(rightWindowName, rightFrame)
Use cv2.imshow
the function of OpenCV to display the left and right frames.
-
cv2.imshow(leftWindowName, leftFrame)
: Use OpenCV'scv2.imshow
function to display the left frame.leftWindowName
is the name of the window on the left, used to identify the window,leftFrame
and is the frame to display. -
cv2.imshow(rightWindowName, rightFrame)
: Use OpenCV'scv2.imshow
function to display the right frame.rightWindowName
is the name of the window on the right, used to identify the window,rightFrame
and is the frame to display.
Responding to keyboard input
key = cv2.waitKey(1)
if key == ord('q'):
break
elif key == ord('s'):
if featureTrackerConfig.cornerDetector.type == dai.FeatureTrackerConfig.CornerDetector.Type.HARRIS:
featureTrackerConfig.cornerDetector.type = dai.FeatureTrackerConfig.CornerDetector.Type.SHI_THOMASI
print("Switching to Shi-Thomasi")
else:
featureTrackerConfig.cornerDetector.type = dai.FeatureTrackerConfig.CornerDetector.Type.HARRIS
print("Switching to Harris")
cfg = dai.FeatureTrackerConfig()
cfg.set(featureTrackerConfig)
inputFeatureTrackerConfigQueue.send(cfg)
The above code implements waiting for the user to press a key on the keyboard, and performs different operations according to the key pressed.
-
key = cv2.waitKey(1)
: Wait for the user to press a key on the keyboard,1
which means waiting for 1 millisecond. This function returns the ASCII value of the key. -
if key == ord('q'):
: If the key pressed isq
the ASCII value corresponding to the letter, that is, the user pressesq
the key:break
: Jump out of the loop and end the program.
-
elif key == ord('s'):
: If the key pressed iss
the ASCII value corresponding to the letter, that is, the user pressess
the key:-
if featureTrackerConfig.cornerDetector.type == dai.FeatureTrackerConfig.CornerDetector.Type.HARRIS:
: Check whether the type of the current corner detector is Harris corner detector.-
featureTrackerConfig.cornerDetector.type = dai.FeatureTrackerConfig.CornerDetector.Type.SHI_THOMASI
: If it is a Harris corner detector, switch the corner detector type to Shi-Thomasi corner detector.print("Switching to Shi-Thomasi")
: Print a message indicating that a switch to the Shi-Thomasi corner detector has been made.
-
else:
: If the type of the current corner detector is not Harris corner detector.-
featureTrackerConfig.cornerDetector.type = dai.FeatureTrackerConfig.CornerDetector.Type.HARRIS
: Switches the corner detector type back to the Harris corner detector. -
print("Switching to Harris")
: Print a message indicating that the Harris corner detector has been switched back.
-
-
-
cfg = dai.FeatureTrackerConfig()
: Create a newdai.FeatureTrackerConfig
object. -
cfg.set(featureTrackerConfig)
: Copies the current feature tracker configurationfeatureTrackerConfig
into the newly created object. -
inputFeatureTrackerConfigQueue.send(cfg)
: Sends the feature tracker configuration object to the namedinputFeatureTrackerConfigQueue
queue.
-
Setup 12: Run the program
Enter the following command in the terminal to run the program
python main.py
Run the program and see the effect