OpenCV系列 - 作者:cc 原链接:https://www.cnblogs.com/ff888/p/16783806.html
什么是轮廓?
SetWorkingDir A_ScriptDir hOpencv := DllCall("LoadLibrary", "str", "opencv_world455.dll", "ptr") hOpencvCom := DllCall("LoadLibrary", "str", "autoit_opencv_com455.dll", "ptr") DllCall("autoit_opencv_com455.dll\DllInstall", "int", 1, "wstr", A_IsAdmin = 0 ? "user" : "", "cdecl") cv := ComObject("OpenCV.cv") img := cv.imread("12.png") cv.imshow("Image1", img) img_ray := cv.cvtColor(img, CV_COLOR_BGR2GRAY:=6) ;这里获取threshold()的双返回值有三种方法 ; 一 ; thresh_img := ComObject("OpenCV.cv.MAT") ; ret := cv.threshold(img_ray, 127, 255, CV_THRESH_BINARY:=0, thresh_img) ; contours := cv.findContours(thresh_img, CV_RETR_TREE:=3, CV_CHAIN_APPROX_SIMPLE:=2) ; 二 ; ret := cv.threshold(img_ray, 127, 255, CV_THRESH_BINARY:=0) ; thresh_img := cv.extended()[1] ; contours := cv.findContours(thresh_img, CV_RETR_TREE:=3, CV_CHAIN_APPROX_SIMPLE:=2) ; 三 cv.threshold(img_ray,100, 255, CV_THRESH_BINARY:=0) ret := cv.extended()[0] thresh_img := cv.extended()[1] contours := cv.findContours(thresh_img, CV_RETR_TREE:=3, CV_CHAIN_APPROX_SIMPLE:=2) hierarchy := cv.extended()[1] ; 参数 ; 在 cv.findContours() 函数中有三个参数, ; 第一个是源图像, ; 第二个是轮廓检索模式, ; 第三个是轮廓逼近方法,并输出轮廓和层次。 ; 返回值 ; contours:图像轮廓坐标,是一个链表 ; hierarchy:[Next, Previous, First Child, Parent] ; 如果我们打印出cv.findContours()函数的返回值hierarchy,会发现它是一个包含4个值的数组:[Next, Previous, First Child, Parent] ; Next:与当前轮廓处于同一层级的下一条轮廓 ; 举例来说,前面图中跟0处于同一层级的下一条轮廓是1,所以Next=1;同理,对轮廓1来说,Next=2;那么对于轮廓2呢?没有与它同一层级的下一条轮廓了,此时Next=-1。 ; Previous:与当前轮廓处于同一层级的上一条轮廓 ; 跟前面一样,对于轮廓1来说,Previous=0;对于轮廓2,Previous=1;对于轮廓2a,没有上一条轮廓了,所以Previous=-1。 ; First Child:当前轮廓的第一条子轮廓 ; 比如对于轮廓2,第一条子轮廓就是轮廓2a,所以First Child=2a;对轮廓3,First Child=3a。 ; Parent:当前轮廓的父轮廓 ; 比如2a的父轮廓是2,Parent=2;轮廓2没有父轮廓,所以Parent=-1。
如何绘制轮廓?
cv.drawContours(img, contours, -1, ComArrayMake([0,0,255]), 3) ComArrayMake(inputArray) { arr := ComObjArray(VT_VARIANT:=12, inputArray.Length) Loop inputArray.Length { arr[A_Index-1] := inputArray[A_Index] } return arr }
要绘制单个轮廓,请说第四个轮廓:
cv.drawContours(img, contours, 3, ComArrayMake([0,0,255]), 3)
但是在大多数情况下,以下方法会很有用:
cnt := contours[0] cv.drawContours(img, ComArrayMake([cnt]), 0, ComArrayMake([0,0,255]), 3)
轮廓近似法
轮廓特征
1.图像矩
SetWorkingDir A_ScriptDir hOpencv := DllCall("LoadLibrary", "str", "opencv_world455.dll", "ptr") hOpencvCom := DllCall("LoadLibrary", "str", "autoit_opencv_com455.dll", "ptr") DllCall("autoit_opencv_com455.dll\DllInstall", "int", 1, "wstr", A_IsAdmin = 0 ? "user" : "", "cdecl") cv := ComObject("OpenCV.cv") img := cv.imread("jiantou.png") cv.imshow("Image1", img) img_ray := cv.cvtColor(img, CV_COLOR_BGR2GRAY:=6) ;这里获取threshold()的双返回值有三种方法 ; 一 ; thresh_img := ComObject("OpenCV.cv.MAT") ; ret := cv.threshold(img_ray, 127, 255, CV_THRESH_BINARY:=0, thresh_img) ; contours := cv.findContours(thresh_img, CV_RETR_TREE:=3, CV_CHAIN_APPROX_SIMPLE:=2) ; 二 ; ret := cv.threshold(img_ray, 127, 255, CV_THRESH_BINARY:=0) ; thresh_img := cv.extended()[1] ; contours := cv.findContours(thresh_img, CV_RETR_TREE:=3, CV_CHAIN_APPROX_SIMPLE:=2) ; 三 cv.threshold(img_ray, 100, 255, CV_THRESH_BINARY:=0) ret := cv.extended()[0] thresh_img := cv.extended()[1] contours := cv.findContours(thresh_img, CV_RETR_TREE:=3, CV_CHAIN_APPROX_SIMPLE:=2) hierarchy := cv.extended()[1] cnt := contours[0] M := cv.moments(cnt) ;M_ji 表示空间矩 ;矩 m_00 给出了轮廓的区域,这等价于函数cv2.contourArea()。 m00 := M.m00 m10 := M.m10 m01 := M.m01 m20 := M.m20 m11 := M.m11 m02 := M.m02 m30 := M.m30 m21 := M.m21 m12 := M.m12 m03 := M.m03 ;Mu_ji 表示中心矩 mu20 := M.mu20 mu11 := M.mu11 mu02 := M.mu02 mu30 := M.mu30 mu21 := M.mu21 mu12 := M.mu12 mu03 := M.mu03 ;Nu_jl 表示归一化中心矩 nu20 := M.nu20 nu11 := M.nu11 nu02 := M.nu02 nu30 := M.nu30 nu21 := M.nu21 nu12 := M.nu12 nu03 := M.nu03 MsgBox("m00: " m00 "`n" "m10: " m10 "`n" "m01: " m01 "`n" "m20: " m20 "`n" "m11: " m11 "`n" "m02: " m02 "`n" "m30: " m30 "`n" "m21: " m21 "`n" "m12: " m12 "`n" "m03: " m03 "`n" , "空间矩" ) MsgBox("mu20: " mu20 "`n" "mu11: " mu11 "`n" "mu02: " mu02 "`n" "mu30: " mu30 "`n" "mu21: " mu21 "`n" "mu12: " mu12 "`n" "mu03: " mu03 "`n" , "中心矩" ) MsgBox("nu20: " nu20 "`n" "nu11: " nu11 "`n" "nu02: " nu02 "`n" "nu30: " nu30 "`n" "nu21: " nu21 "`n" "nu12: " nu12 "`n" "nu03: " nu03 "`n" , "归一化中心矩" )
在图像矩中,您可以提取有用的数据,例如面积,质心等。质心由关系C给出 $C_x = \frac{M_{10}}{M_{00}}$ 和 $C_y = \frac{M_{01}}{M_{00}}$。可以按照以下步骤进行:
cx := Integer(M.m10/M.m00) cy := Integer(M.m01/M.m00) MsgBox "质心X: " cx "`n" "质心Y: " cy
接下来在坐标处画圆
效果图:
2.轮廓面积
area := cv.contourArea(cnt)
MsgBox "轮廓面积: " area
3.轮廓周长
perimeter := cv.arcLength(cnt, ComValue(0xB, -1)) ;第二个参数给了true
MsgBox perimeter
4.轮廓近似
在数字化时,要对曲线进行采样,即在曲线上取有限个点,将其变为折线,并且能够在一定程度上保持原有的形状。
经典的Douglas-Peucker算法步骤如下:
(1)在曲线首尾两点A,B之间连接一条直线AB,该直线为曲线的弦;
(2)得到曲线上离该直线段距离最大的点C,计算其与AB的距离d;
(3)比较该距离与预先给定的阈值threshold的大小,如果小于threshold,则该直线段作为曲线的近似,该段曲线处理完毕。
(4)如果距离大于阈值,则用C将曲线分为两段AC和BC,并分别对两段取信进行1~3的处理。
(5)当所有曲线都处理完毕时,依次连接各个分割点形成的折线,即可以作为曲线的近似。
SetWorkingDir A_ScriptDir hOpencv := DllCall("LoadLibrary", "str", "opencv_world455.dll", "ptr") hOpencvCom := DllCall("LoadLibrary", "str", "autoit_opencv_com455.dll", "ptr") DllCall("autoit_opencv_com455.dll\DllInstall", "int", 1, "wstr", A_IsAdmin = 0 ? "user" : "", "cdecl") cv := ComObject("OpenCV.cv") img := cv.imread("jinsi.png") cv.imshow("Image", img) img_ray := cv.cvtColor(img, CV_COLOR_BGR2GRAY:=6) cv.threshold(img_ray, 100, 255, CV_THRESH_BINARY:=0) ret := cv.extended()[0] thresh_img := cv.extended()[1] contours := cv.findContours(thresh_img, CV_RETR_TREE:=3, CV_CHAIN_APPROX_SIMPLE:=2) hierarchy := cv.extended()[1] cnt := contours[0] epsilon := 0.01*cv.arcLength(cnt, ComValue(0xB, -1)) approx := cv.approxPolyDP(cnt, epsilon, ComValue(0xB, -1)) cv.drawContours(img, ComArrayMake([approx]), 0, ComArrayMake([0,0,255]), 3) cv.imshow("Image1", img) cv.waitKey() cv.destroyAllWindows() ComArrayMake(inputArray) { arr := ComObjArray(VT_VARIANT:=12, inputArray.Length) Loop inputArray.Length { arr[A_Index-1] := inputArray[A_Index] } return arr }
下面,在第二张图片中,绿线显示了 精度 epsilon = 10% 时的近似曲线。第三幅图显示了精度 epsilon = 1% 时的情况。第三个参数指定曲线是否闭合。
5.凸包
逼近多边形是某个图像轮廓的高度近似,而凸包的提出是为了简化逼近多边形的。其实,凸包跟逼近多边形很像,只不过它是物体最外层的“凸”多边形。
简单的概括,凸包是指完全包含原有轮廓,并且仅由轮廓上的点所构成的多边形。凸包的特点是每一处都是凸的,即在凸包内连接任意两点的直线都在凸包的内部,并且任意连续3个点的内角小于180度。
凸包外观看起来与轮廓逼近相似,但并非如此(在某些情况下两者可能提供相同的结果)。在这里,**cv.convexHull()** 函数检查曲线是否存在凸凹缺陷并对其进行校正。一般而言,凸曲线是始终凸出或至少平坦的曲线。如果在内部凸出,则称为凸度缺陷。
hull := cv.convexHull(points[, hull[, clockwise[, returnPoints]]])
参数详细信息:
- points: 就是我们传入的轮廓。
- hull: 是输出,通常我们避免它。
- clockwise:方向标记。如果为True,则输出凸包为顺时针方向。否则,其方向为逆时针方向。
- returnPoints:默认情况下为True。然后返回船体点的坐标。如果为False,则返回与船体点相对应的轮廓点的索引。
因此,要获得如上图所示的凸包,以下内容就足够了:
hull := cv.convexHull(cnt)
SetWorkingDir A_ScriptDir hOpencv := DllCall("LoadLibrary", "str", "opencv_world455.dll", "ptr") hOpencvCom := DllCall("LoadLibrary", "str", "autoit_opencv_com455.dll", "ptr") DllCall("autoit_opencv_com455.dll\DllInstall", "int", 1, "wstr", A_IsAdmin = 0 ? "user" : "", "cdecl") cv := ComObject("OpenCV.cv") img := cv.imread("tubao.png") cv.imshow("Image", img) img_ray := cv.cvtColor(img, CV_COLOR_BGR2GRAY:=6) cv.threshold(img_ray, 100, 255, CV_THRESH_BINARY:=0) ret := cv.extended()[0] thresh_img := cv.extended()[1] contours := cv.findContours(thresh_img, CV_RETR_TREE:=3, CV_CHAIN_APPROX_SIMPLE:=2) hierarchy := cv.extended()[1] cnt := contours[0] hull := cv.convexHull(cnt) cv.drawContours(img, ComArrayMake([hull]), 0, ComArrayMake([0,0,255]), 2) cv.imshow("Image1", img) cv.waitKey() cv.destroyAllWindows() ComArrayMake(inputArray) { arr := ComObjArray(VT_VARIANT:=12, inputArray.Length) Loop inputArray.Length { arr[A_Index-1] := inputArray[A_Index] } return arr }
凸包缺陷
convexityDefects := cv.convexityDefects(contour, convexhull)
SetWorkingDir A_ScriptDir cv := ComObject("OpenCV.cv") out := ComObject("OpenCV.cv.MAT") img := cv.imread("tubao.png") cv.imshow("Image", img) img_ray := cv.cvtColor(img, CV_COLOR_BGR2GRAY:=6) cv.threshold(img_ray, 100, 255, CV_THRESH_BINARY:=0) ret := cv.extended()[0] thresh_img := cv.extended()[1] contours := cv.findContours(thresh_img, CV_RETR_TREE:=3, CV_CHAIN_APPROX_SIMPLE:=2) hierarchy := cv.extended()[1] cnt := contours[0] vofp := ComObject("OpenCV.VectorOfVectorOfPoint") contours := cv.findContours(thresh_img, CV_RETR_TREE:=3, CV_CHAIN_APPROX_SIMPLE:=2, vofp) vp := vofp[0] ; epsilon := 0.01*cv.arcLength(cnt, ComValue(0xB, -1)) ; approx := cv.approxPolyDP(cnt, epsilon, ComValue(0xB, -1)) hull := cv.convexHull(cnt) hull1 := cv.convexHull(cnt,,, ComValue(0xB, 0)) defects := cv.convexityDefects(cnt,hull1) data := defects.data loop(defects.rows) { r := A_Index loop(defects.cols) { c := A_Index loop(defects.channels) { f := numget(data, (r - 1) * (defects.cols * defects.channels * 4) + (c - 1) * defects.channels * 4 + (A_Index - 1) * 4 , "int") a .= f "-" if(A_Index == 3) { px := numget(cnt.data, f * 8, "Int") py := numget(cnt.data, f * 8 + 4, "Int") ax := vp[f][0] ay := vp[f][1] cv.circle(img,ComArrayMake([px,py]), 3, ComArrayMake([0,0,255]), -1) } } a .= " | " } a .= "`n" } ;cv.drawContours(img, ComArrayMake([hull]), 0, ComArrayMake([0,0,255]), 2) cv.imshow("Image1", img) cv.waitKey() cv.destroyAllWindows() ComArrayMake(inputArray) { arr := ComObjArray(VT_VARIANT:=12, inputArray.Length) Loop inputArray.Length { arr[A_Index-1] := inputArray[A_Index] } return arr }
6.检查凸度
k := cv.isContourConvex(cnt)
MsgBox(k)
7.边界矩形
7.1直边界矩形(外接矩形)
一个直矩形(就是没有旋转的矩形)。它不会考虑对象是否旋转。 所以边界矩形的面积不是最小的。可以使用函数 cv.boundingRect() 查找得到。返回值 (x, y)为矩形左上角的坐标,( w, h)是矩形的宽和高。
SetWorkingDir A_ScriptDir hOpencv := DllCall("LoadLibrary", "str", "opencv_world455.dll", "ptr") hOpencvCom := DllCall("LoadLibrary", "str", "autoit_opencv_com455.dll", "ptr") DllCall("autoit_opencv_com455.dll\DllInstall", "int", 1, "wstr", A_IsAdmin = 0 ? "user" : "", "cdecl") cv := ComObject("OpenCV.cv") img := cv.imread("xiefangkuai.png") img_ray := cv.cvtColor(img, CV_COLOR_BGR2GRAY:=6) cv.threshold(img_ray, 127, 255, CV_THRESH_BINARY:=0) ret := cv.extended()[0] thresh_img := cv.extended()[1] contours := cv.findContours(thresh_img, CV_RETR_TREE:=3, CV_CHAIN_APPROX_SIMPLE:=2) hierarchy := cv.extended()[1] cnt := contours[0] For k in contours{ i := cv.boundingRect(k) img := cv.rectangle(img, i, ComArrayMake([0, 0, 255]), 2) } cv.imshow("Image", img) cv.waitKey() cv.destroyAllWindows() ComArrayMake(inputArray) { arr := ComObjArray(VT_VARIANT:=12, inputArray.Length) Loop inputArray.Length { arr[A_Index-1] := inputArray[A_Index] } return arr }
7.2旋转的边界矩形(最小外接矩形)
这个边界矩形是面积最小的,因为它考虑了对象的旋转。用到的函数为 cv2.minAreaRect()。返回的是一个Box2D 结构,其中包含矩形左上角角点的坐标( x, y),矩形的宽和高( w, h),以及旋转角度。但是要绘制这个矩形需要矩形的 4 个角点,可以通过函数 cv.boxPoints() 获得。
s := cv.minAreaRect(cnt) a := cv.boxPoints(s) arr := [] loop 8{ arr.push(Integer(cv.boxPoints(s)[A_Index-1])) } cv.polylines(img, OpencvAHK_ConstPointConst([[arr[1], arr[2]], [arr[3],arr[4]],[arr[5],arr[6]],[arr[7],arr[8]]]), ComValue(0xB, -1), ComArrayMake([255,0,0]), 3)
8.最小外接圆
center := cv.minEnclosingCircle(cnt) radius := cv.extended()[1] cv.circle(img, center, radius, ComArrayMake([0,255,0]), 2)
9.拟合椭圆
ellipse := cv.fitEllipse(cnt)
cv.ellipse(img,ellipse,ComArrayMake([0,255,0]),2)
10.拟合线
图像处理中,通常会遇到根据给定的点集(比如轮廓)拟合出一条直线的情形。opencv2和opencv3中提供了一个专门用于直线拟合的函数**cv.fitLine()**。
rows := img.rows() cols := img.cols() line := cv.fitLine(cnt, CV_DIST_L2:=2, 0, 0.01, 0.01) vx := line[0] vy := line[1] x := line[2] y := line[3] lefty := Integer((-x*vy/vx) + y) righty := Integer(((cols-x)*vy/vx) + y) cv.line(img, ComArrayMake([cols-1, righty]), ComArrayMake([0,lefty]), ComArrayMake([255,0,0]), 2)
轮廓属性
1.长宽比
aspect := cv.boundingRect(cnt) x := aspect[0] y := aspect[1] w := aspect[2] h := aspect[3] aspect_ratio := float(w)/h MsgBox("长宽比-直边界矩形(外接矩形):" aspect_ratio)
2.范围
area := cv.contourArea(cnt) aspect := cv.boundingRect(cnt) w := aspect[2] h := aspect[3] rect_area := w*h extent := float(area)/rect_area MsgBox("范围-轮廓区域与边界矩形区域的比率" extent)
3.固实性
area := cv.contourArea(cnt) hull := cv.convexHull(cnt) hull_area := cv.contourArea(hull) solidity := float(area)/hull_area MsgBox("固实性-轮廓面积与其凸包面积的比率:" solidity)
4.等效直径
area := cv.contourArea(cnt) equi_diameter := sqrt(4*area/3.141592653589793) MsgBox("等效直径-面积与轮廓面积相同的圆的直径:" equi_diameter)
5.方向
ellipse := cv.fitEllipse(cnt) MsgBox(ellipse.angle())
6.遮罩和像素点
mat := ComObject("OpenCV.cv.MAT") mask := mat.zeros(img.size(), CV_8UC1:= cv2.CV_MAKETYPE(cv2.CV_8U, 1)) cv.circle(mask,ComArrayMake([300,263]), 140, ComArrayMake([255, 255, 255]), -1) pixelpoints := cv.findNonZero(mask)
7.最大值,最小值及其位置
cv.minMaxLoc(img_ray, mask) min_val := cv.extended()[0] max_val := cv.extended()[1] min_loc := cv.extended()[2] max_loc := cv.extended()[3] MsgBox("最小值:" min_val "最大值:" max_val "最小位置:" "x:" min_loc[0] "y:" min_loc[1] "最大位置:" "x:" max_loc[0] "y:" max_loc[1])
8.平均颜色或平均强度
mean_val := cv.mean(img, mask) MsgBox("B通道均值:" mean_val[0] "`n" "G通道均值:" mean_val[1] "`n" "R通道均值:" mean_val[2] "`n")
9.极端点
dbgba优化整理OpenCV系列示例打包下载20240513:
天黑版opencv_ahk.dll使用(改变了调用方式,优化速度…)
相关文件:https://wwz.lanzouw.com/iAkK803eaaud
cv2.ahk和log.ahk来自社区群友zzZ…
可以用文件中的天黑版的v2h版ahk运行。
示例:轮廓
#Dllload lib #DllLoad opencv_ahk.dll #include <cv2> #include <log> SetWorkingDir A_ScriptDir ;初始化opencv模块 cv := ObjFromPtr(DllCall('opencv_ahk.dll\opencv_init', 'ptr', DllCall(A_AhkPath '\ahkGetApi', 'ptr'), 'cdecl ptr')) img := cv.imread("image/11.png") cv.imshow("image", img) cv.cvtColor(img, img_grey := cv.Mat(), cv2.CV_COLOR_BGR2GRAY) cv.Canny(img_grey, canny := cv.Mat(), 80.0, 160.0) k := cv.getStructuringElement(cv2.CV_MORPH_RECT, [3, 3], [-1, -1]) cv.dilate(canny, dilation := cv.MAT(), k) cv.threshold(dilation, thresh_img := cv.MAT(), 127, 255, cv2.CV_THRESH_BINARY) cv.findContours(thresh_img, contours := cv.Vector_Vector_Point(), cv2.CV_RETR_TREE, cv2.CV_CHAIN_APPROX_SIMPLE) cv.drawContours(img, contours, 0, [0,255,0], 3) ;矩 M := cv.moments(contours[0]) m00 := M.m00 log.info('m00:' m00) ;轮廓面积 area := cv.contourArea(contours[0]) log.info('轮廓面积:' area) ;轮廓周长 perimeter := cv.arcLength(contours[0], true) log.info('轮廓周长:' perimeter) ;轮廓近似 epsilon := 0.01*cv.arcLength(contours[0], true) cv.approxPolyDP(contours[0], approx := cv.Vector_Point(), epsilon, true) ;cv.drawContours(img, cv.Vector_Vector_Point([approx]), 0, [0, 0, 255], 3) ;凸包 cv.convexHull(contours[0], hull := cv.Vector_Point()) ;cv.drawContours(img, cv.Vector_Vector_Point([hull]), 0, [0, 0, 255], 2) ;检查凸度 k := cv.isContourConvex(contours[0]) log.info('凸度:' k) ;直边界矩形(外接矩形) box := cv.boundingRect(contours[0]) x := box[1] y := box[2] w := box[3] h := box[4] cv.rectangle(img, [x, y], [x+w, y+h], [0,255,0], 2) ;旋转的边界矩形(最小外接矩形) rect := cv.minAreaRect(contours[0]) ;log.info(rect) cv.boxPoints(rect, box1 := cv.Vector_Point2f()) cv.polylines(img, cv.Vector_Point(box1.toarray()), true, [0, 255, 255], 1) ;最小外接圆 cv.minEnclosingCircle(contours[0], ¢er, &radius) ;log.info(center) ;.info(radius) cv.circle(img, center, radius, [0, 0, 255], 2) ;拟合椭圆 ellipse := cv.fitEllipse(contours[0]) cv.ellipse(img, ellipse, [0,255,0], 2) ;拟合线 cv.fitLine(contours[0], line := cv.vector_float(), cv2.CV_DIST_HUBER, 0, 0.01, 0.01) ;log.info(line[0]) vx := line[0] vy := line[1] x := line[2] y := line[3] lefty := Integer((-x*vy/vx) + y) righty := Integer(((img.cols-x)*vy/vx) + y) cv.line(img, [img.cols-1, righty], [0,lefty], [255,0,0], 2) ;轮廓属性 ;长宽比 box := cv.boundingRect(contours[0]) x := box[1] y := box[2] w := box[3] h := box[4] aspect_ratio := float(w)/h log.info('长宽比-(外接矩形):' aspect_ratio) ;范围 area := cv.contourArea(contours[0]) aspect := cv.boundingRect(contours[0]) w := aspect[2] h := aspect[3] rect_area := w*h extent := float(area)/rect_area log.info("范围-(轮廓区域与边界矩形区域的比率):" extent) ;固实性 area := cv.contourArea(contours[0]) cv.convexHull(contours[0], hull := cv.Vector_Point()) hull_area := cv.contourArea(hull) solidity := float(area)/hull_area log.info("固实性-(轮廓面积与其凸包面积的比率):" solidity) ;等效直径 area := cv.contourArea(contours[0]) equi_diameter := sqrt(4*area/3.141592653589793) log.info("等效直径-(面积与轮廓面积相同的圆的直径):" equi_diameter) ;方向 ellipse := cv.fitEllipse(contours[0]) log.info('方向是物体指向的角度:' ellipse[5]) ;遮罩和像素点 mask := cv.MAT(img.rows, img.cols, cv2.CV_8UC1, [0, 0, 0]) ;注意单通道 cv.circle(mask, [100, 60], 40, [255, 255, 255], -1) cv.imshow("image11", mask) cv.findNonZero(mask, pixelpoints := cv.Vector_Point()) log.info(pixelpoints.toarray()) ;最大值,最小值及其位置 cv.minMaxLoc(img_grey, &minVal, &maxVal, &minLoc, &maxLoc) log.info("最小值:" minVal "最大值:" maxVal "最小位置:" "x:" minLoc[1] "y:" minLoc[2] "最大位置:" "x:" maxLoc[1] "y:" maxLoc[2]) ;平均颜色或平均强度(BGR) mean_val := cv.mean(img, mask) log.info(mean_val) ;极端点 log.info(contours[0].toarray()) x_array := [] y_array := [] max_right := 0 max_left := 9999 max_top := 9999 max_bot := 0 loop contours[0].Size{ x_array.push(contours[0][A_Index-1][1]) y_array.push(contours[0][A_Index-1][2]) if x_array[A_Index] > max_right{ max_right := x_array[A_Index] max_right_y := contours[0][A_Index-1][2] } if x_array[A_Index] < max_left{ max_left := x_array[A_Index] max_left_y := contours[0][A_Index-1][2] } if y_array[A_Index] > max_bot{ max_bot := y_array[A_Index] max_bot_x := contours[0][A_Index-1][1] } if y_array[A_Index] < max_top{ max_top := y_array[A_Index] max_top_x := contours[0][A_Index-1][1] } } log.info('最右侧点:' max_right ' ' max_right_y) log.info('最顶部点:' max_bot_x ' ' max_bot) log.info('最左侧点:' max_left ' ' max_left_y) log.info('最底部点:' max_top_x ' ' max_top) cv.circle(img, [max_right, max_right_y], 5, [0, 0, 255], -1) cv.circle(img, [max_bot_x, max_bot], 5, [0, 0, 255], -1) cv.circle(img, [max_left, max_left_y], 5, [0, 0, 255], -1) cv.circle(img, [max_top_x, max_top], 5, [0, 0, 255], -1) cv.imshow("image1", img) cv.waitKey() cv.destroyAllWindows()
匹配形状
#Dllload lib #DllLoad opencv_ahk.dll #include <cv2> #include <log> SetWorkingDir A_ScriptDir ;初始化opencv模块 cv := ObjFromPtr(DllCall('opencv_ahk.dll\opencv_init', 'ptr', DllCall(A_AhkPath '\ahkGetApi', 'ptr'), 'cdecl ptr')) img1 := cv.imread("image/111.png") img2 := cv.imread("image/123.png") cv.imshow("image", img2) cv.cvtColor(img1, img_grey1 := cv.Mat(), cv2.CV_COLOR_BGR2GRAY) cv.threshold(img_grey1, thresh_img1 := cv.MAT(), 127, 255, cv2.CV_THRESH_BINARY) cv.findContours(thresh_img1, contours1 := cv.Vector_Vector_Point(), cv2.CV_RETR_TREE, cv2.CV_CHAIN_APPROX_SIMPLE) cv.drawContours(img1, contours1, 0, [0, 0, 255], 3) cv.cvtColor(img2, img_grey2 := cv.Mat(), cv2.CV_COLOR_BGR2GRAY) cv.threshold(img_grey2, thresh_img2 := cv.MAT(), 127, 255, cv2.CV_THRESH_BINARY) cv.findContours(thresh_img2, contours2 := cv.Vector_Vector_Point(), cv2.CV_RETR_TREE, cv2.CV_CHAIN_APPROX_SIMPLE) cnt1 := contours1[0] loop 3{ M := cv.moments(contours2[A_Index-1]) cx := Integer(M.m10/M.m00) cy := Integer(M.m01/M.m00) cv.circle(img2, [cx, cy], 3, [0, 0, 255], -1) cnt2 := contours2[A_Index-1] cv.drawContours(img2, contours2, A_Index-1, [0, 0, 255], 3) ret := cv.matchShapes(cnt1, cnt2, 1, 0.0) cv.putText(img2, ret, [cx, cy], 0, 0.5, [255, 0, 255], 1) log.info(ret) } cv.imshow("image1", img1) cv.imshow("image2", img2) cv.waitKey() cv.destroyAllWindows()
匹配自身结果=0.0
匹配旋转后的自身结果=0.008218551978777078
匹配矩形结果=0.3271618191421985
有错误请联系我改正!
天黑主项目地址:https://github.com/thqby/opencv_ahk
本系列所有贡献者(AutoHotKey中文社区群友)不分先后:天黑请闭眼,zzZ…,演好自己,僵尸,城西,Tebayaki。
评论(0)