二进制阈值图像-> 应用精明的边缘检测-> findContour(),这会改善轮廓检测吗?
Posted
技术标签:
【中文标题】二进制阈值图像-> 应用精明的边缘检测-> findContour(),这会改善轮廓检测吗?【英文标题】:binary thresholded image-> apply canny edge detection -> findContour(), does this improve Contour detection? 【发布时间】:2019-09-22 18:43:17 【问题描述】:我正在尝试检测黄色物体。我在 HSV 配色方案中执行颜色分割,使用 cvInRange 对黄色范围进行阈值,它返回一个二进制阈值掩码,检测到的区域以白色显示,而其他颜色被忽略并涂黑。我认为获得边缘不仅会减少 findContour() 的计算,而且会使改变边缘平面更加明显。因此,不要这样做:
binary thresholded image -> findContour()
我做到了:
binary thresholded image -> Canny() -> findContour() instead.
请参阅下面的代码 + 显示的图像帧输出的附加图片。
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame)
InputFrame = inputFrame.rgba();
Core.transpose(InputFrame,mat1); //transpose mat1(src) to mat2(dst), sorta like a Clone!
Imgproc.resize(mat1,mat2,InputFrame.size(),0,0,0); // params:(Mat src, Mat dst, Size dsize, fx, fy, interpolation) Extract the dimensions of the new Screen Orientation, obtain the new orientation's surface width & height. Try to resize to fit to screen.
Core.flip(mat2,InputFrame,-1); // mat3 now get updated, no longer is the Origi inputFrame.rgba BUT RATHER the transposed, resized, flipped version of inputFrame.rgba().
int rowWidth = InputFrame.rows();
int colWidth = InputFrame.cols();
Imgproc.cvtColor(InputFrame,InputFrame,Imgproc.COLOR_RGBA2RGB);
Imgproc.cvtColor(InputFrame,InputFrame,Imgproc.COLOR_RGB2HSV);
//============= binary threshold image to Yellow mask ============
Lower_Yellow = new Scalar(21,150,150); //HSV color scale H to adjust color, S to control color variation, V is indicator of amt of light required to be shine on object to be seen.
Upper_Yellow = new Scalar(31,255,360); //HSV color scale
Core.inRange(InputFrame,Lower_Yellow, Upper_Yellow, maskForYellow);
//============== Apply Morphology to remove noise ===================
final Size kernelSize = new Size(5, 5); //must be odd num size & greater than 1.
final Point anchor = new Point(-1, -1); //default (-1,-1) means that the anchor is at the center of the structuring element.
final int iterations = 1; //number of times dilation is applied. https://docs.opencv.org/3.4/d4/d76/tutorial_js_morphological_ops.html
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, kernelSize);
Imgproc.morphologyEx(maskForYellow, yellowMaskMorphed, Imgproc.MORPH_CLOSE, kernel, anchor, iterations); //dilate first to remove then erode. White regions becomes more pronounced, erode away black regions
//=========== Apply Canny to obtain edge detection ==============
Mat mIntermediateMat = new Mat();
Imgproc.GaussianBlur(yellowMaskMorphed,mIntermediateMat,new Size(9,9),0,0); //better result than kernel size (3,3, maybe cos reference area wider, bigger, can decide better whether inrange / out of range.
Imgproc.Canny(mIntermediateMat, mIntermediateMat, 5, 120); //try adjust threshold //https://***.com/questions/25125670/best-value-for-threshold-in-canny
//============ apply findContour()==================
List<MatOfPoint> contours = new ArrayList<>();
Mat hierarchy = new Mat();
Imgproc.findContours(mIntermediateMat, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0, 0));
//=========== Use contourArea to find LargestBlob contour ===============
double maxArea1 = 0;
int maxAreaIndex1 = 0;
//MatOfPoint max_contours = new MatOfPoint();
Rect r = null;
ArrayList<Rect> rect_array = new ArrayList<Rect>();
for(int i=0; i < contours.size(); i++)
//if(Imgproc.contourArea(contours.get(i)) > 300) //Size of Mat contour @ that particular point in ArrayList of Points.
double contourArea1 = Imgproc.contourArea(contours.get(i));
//Size of Mat contour @ that particular point in ArrayList of Points.
if (maxArea1 < contourArea1)
maxArea1 = contourArea1;
maxAreaIndex1 = i;
//maxArea1 = Imgproc.contourArea(contours.get(i)); //assigned but nvr used
//max_contours = contours.get(i);
r = Imgproc.boundingRect(contours.get(maxAreaIndex1));
rect_array.add(r); //will only have 1 r in the array eventually, cos we will only take the one w largestContourArea.
Imgproc.cvtColor(InputFrame, InputFrame, Imgproc.COLOR_HSV2RGB);
//============ plot largest blob contour ================
if (rect_array.size() > 0) //if got more than 1 rect found in rect_array, draw them out!
Iterator<Rect> it2 = rect_array.iterator(); //only got 1 though, this method much faster than drawContour, wont lag. =D
while (it2.hasNext())
Rect obj = it2.next();
//if
Imgproc.rectangle(InputFrame, obj.br(), obj.tl(),
new Scalar(0, 255, 0), 1);
原始黄色对象1
HSV 色彩空间中的对象2
cvInrRange 变为黄色后 - 返回二进制阈值掩码 3
应用 Canny 边缘检测后返回的边缘4
【问题讨论】:
【参考方案1】:我已经尝试了这两种方法,发现在阈值图像上应用 Canny() 有助于使检测更快、更稳定,因此我将这部分保留在我的代码中。我的猜测是,在我们应用 Canny() 之后可能需要计算的点更少,它还有助于使边缘更明显,因此在 findContour() 中计算变得更容易和更快。
【讨论】:
以上是关于二进制阈值图像-> 应用精明的边缘检测-> findContour(),这会改善轮廓检测吗?的主要内容,如果未能解决你的问题,请参考以下文章
图像分割基于阙值+边缘检测+区域法图像分割matlab源码含GUI