赞
踩
Hough Line Transform:前提:边缘检测已经完成,基于霍夫变换
可以通过(theta,r)唯一表示一个点。
把过三个点的全部直线以某一角度全部计算出来,如果三个点的直线有相同的,则说明有一条直线过了这三个点。
至于为啥用(theta, r)而不是斜率k和截距b来表示一条直线,是因为利用y = kx + b来表示直线时,存在斜率k无穷大的情况,无法计算。并且theta为0到2*pi, 且对于直线来说r一定小于等于b,所以计算的数值也相对较小。
参考博客
def line_detection(image): blurred = cv.GaussianBlur(image, (3, 3), 0) gray =cv.cvtColor(image,cv.COLOR_BGR2GRAY) # edges=cv.Canny(gray,50,150,apertureSize=3) #apertureSize类似于步长 # edges=cv.Canny(blurred,50,150,apertureSize=3) #apertureSize类似于步长 edges=cv.Canny(image,50,150,apertureSize=3) #apertureSize类似于步长 lines =cv.HoughLines(edges,1,np.pi/180,200) #200:threshold,累加平面的阈值参数,即识别某部分为图中的一条直线时它在累加平面中必须达到的值。 # 大于阈值threshold的线段才可以被检测通过并返回到结果中。 # --------------------------- # 自己计算过程如下: for line in lines: rho,theta=line[0] #r,角度 霍夫空间 a=np.cos(theta) #余弦值 b=np.sin(theta) x0=a*rho #这个点的x坐标 y0=b*rho #这个点的y坐标 # x1 stores the rounded off value of (rcos(theta)-1000sin(theta)) x1 = int(x0 + 1000 * (-b)) #其实就是x0,y0这个点按比例增加或者减少一段距离,还在这条直线上的点x1,y1 # y1 stores the rounded off value of (rsin(theta)+1000cos(theta)) y1 = int(y0 + 1000 * (a)) # x2 stores the rounded off value of (rcos(theta)+1000sin(theta)) x2 = int(x0 - 1000 * (-b)) # y2 stores the rounded off value of (rsin(theta)-1000cos(theta)) y2 = int(y0 - 1000 * (a)) cv.line(image,(x1,y1),(x2,y2),(0,0,255),2) cv.imshow("line detect image",image)
def line_detection_possible(image):
gray =cv.cvtColor(image,cv.COLOR_BGR2GRAY)
edges=cv.Canny(gray,50,150,apertureSize=3) #apertureSize类似于步长
lines =cv.HoughLinesP(edges,1,np.pi/180,200,minLineLength=20,maxLineGap=5) #允许断点,可以定义最小长度
for line in lines:
x1,y1,x2,y2=line[0] #r,角度 霍夫空间
cv.line(image,(x1,y1),(x2,y2),(0,0,255),2)
cv.imshow("line detect possible image",image)
直线检测、圆检测:基于霍夫变换
霍夫圆检测对噪声比较敏感,所以要先进行滤波(去噪)
霍夫圆检测基于梯度变换:
def detect_CIRCLES(image):
dst=cv.pyrMeanShiftFiltering(image,10,100)#均值滤波
# dst=cv.GaussianBlur(image,(3,3),0)#高斯滤波
img=cv.cvtColor(dst,cv.COLOR_BGR2GRAY)
circles=cv.HoughCircles(img,cv.HOUGH_GRADIENT,1,20,param1=50,param2=55,minRadius=0,maxRadius=0)
#距圆心半径为20以内归为1个圆,param1较高的阈值传递到Canny边缘检测器,
# param2它是检测阶段圆中心的累加器阈值。它越小,越多。 可能会检测到假圆圈。
circles=np.uint16(np.around(circles))
for i in circles[0,:]:
cv.circle(image,(i[0],i[1]),i[2],[0,0,255],2)#在原图上画圆
cv.circle(image,(i[0],i[1]),2,[255,0,0],2)#画圆心
cv.imshow("circles:",image)
cv.imshow("circles1:",dst)
def measure_object(image): gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY) # 图像转灰度图 # 将灰度图转为二值图 ret是阈值 binary是二值图 ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU) dst = cv.cvtColor(binary, cv.COLOR_GRAY2BGR) # 边缘检测后再次灰度处理 print('threshold value: %s' % ret) # 把阈值打印出来 cv.imshow('binary image', binary) # 把二值图显示出来 # 找目标的轮廓 image, contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) for i, contour in enumerate(contours): area = cv.contourArea(contour) # 计算轮廓的面积 print('area', area) x, y, w, h = cv.boundingRect(contour) # 计算轮廓外接矩形 rate = min(w, h) / max(w, h) # 计算长宽比 print('rate', rate) mm = cv.moments(contour) # 计算轮廓的几何矩 print(type(mm)) # 找轮廓的中心位置 # cx = mm['m10'] / mm['m00'] #就是不对 # cy = mm['m01'] / mm['m00'] # 用个黄色小圆圈把几何图形的中心位置绘制出来 # cv.circle(image, (np.int(cx), np.int(cy)), 3, (0, 255, 255), -1) # 用红色框框把外接矩形绘制出来 cv.rectangle(dst, (x, y), (x + w, y + h), (0, 0, 255), 2) approxCurve = cv.approxPolyDP(contour, 4, True) """ approxPolyDP(curve, epsilon, closed, approxCurve=None) 多边形逼近函数 参数curve表示输入的点集,直接使用轮廓点集contour 参数epsilon表示指定的精度,即原始曲线与近似曲线之间的最大距离 参数closed表示若为true,则说明近似曲线是闭合的,反之,若为false,则断开 参数approxCurve表示输出的点集,当前点集是能最小包容指定点集的,画出来即是一个多边形 """ # print(approxCurve) # 打印每个轮廓的特征点 print(approxCurve.shape) # 打印该点集的shape,第一个数是代表了点的个数,也就是边长连接逼近数 if approxCurve.shape[0] >6: # 显示对圆形的多边形逼近 cv.drawContours(dst, contours, i, (0, 255, 0), 2) if approxCurve.shape[0] == 4: # 显示对四边形的多边形逼近 cv.drawContours(dst, contours, i, (0, 0, 255), 2) if approxCurve.shape[0] == 3: # 显示对三角形的多边形逼近 cv.drawContours(dst, contours, i, (255, 0, 0), 2) if approxCurve.shape[0] == 5: # 显示对五边形的多边形逼近 cv.drawContours(dst, contours, i, (255, 255, 0), 2) cv.imshow("measure-contours", dst)
废话不多说,看效果:如下图对二值图像进行腐蚀和膨胀的效果(如字面意思)
对彩色图像的腐蚀和膨胀效果直观来看其实就是变暗和变亮?
完整代码:
import cv2 as cv import numpy as np # 膨胀和腐蚀支持任意形状的结构元素 (膨胀:最大值替换中心像素;腐蚀:最小值替换中心像素) # 3*3、5*5的结构元素或者模板 data_path='C:\\Users\\22852\\Desktop\\opencv\\data\\' result_path='C:\\Users\\22852\\Desktop\\opencv\\result\\' def erode_demo(image):#腐蚀 gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY) rect,binary=cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU) cv.imshow("binary:", binary) # cv.imwrite("C:\\Users\\22852\\Desktop\\opencv\\result\\binary_handwriting.jpeg",binary) kernel = cv.getStructuringElement(cv.MORPH_RECT,(3,3)) dst = cv.erode(binary,kernel) cv.imshow("eroid:",dst) # cv.imwrite("C:\\Users\\22852\\Desktop\\opencv\\result\\erode_handwriting.jpeg:",dst) def dilate_demo(image):#膨胀 gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY) rect,binary=cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU) cv.imshow("binary:",binary) kernel = cv.getStructuringElement(cv.MORPH_RECT,(3,3)) dst = cv.dilate(binary,kernel) cv.imshow("dilate:",dst) # cv.imwrite("C:\\Users\\22852\\Desktop\\opencv\\result\\dilate_handwriting.jpeg:", dst) src = cv.imread('C:\\Users\\22852\\Desktop\\opencv\\data\\handwriting.jpeg') src1 = cv.imread('C:\\Users\\22852\\Desktop\\opencv\\data\\input.jpg') cv.imshow("input image:", src) cv.imshow("input image1:", src1) kernel = cv.getStructuringElement(cv.MORPH_RECT,(5,5)) dst1 =cv.erode(src1,kernel)#对彩色图像进行腐蚀,更暗 dst2 =cv.dilate(src1,kernel)#对彩色图像进行膨胀,更亮 cv.imshow("erode image:", dst1) cv.imshow("dilate image:", dst2) # cv.imwrite(result_path+'erode_girl.jpg',dst1) # cv.imwrite(result_path+'dilate_girl.jpg',dst2) erode_demo(src) dilate_demo(src) cv.waitKey(0) cv.destroyAllWindows()
cv.morphologyEx(binary,cv.MORPH_OPEN,kernel)
cv.morphologyEx(binary,cv.MORPH_CLOSE,kernel)
def open_demo(image):#开操作 dst = cv.GaussianBlur(image, (5,5), 0) # 高斯滤波 gray=cv.cvtColor(dst,cv.COLOR_BGR2GRAY) rect,binary=cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU) # rect,binary=cv.threshold(gray,0,255,cv.THRESH_BINARY_INV|cv.THRESH_OTSU) cv.imshow("binary:", binary) # cv.imwrite(result_path+"y_binary.jpg:",binary) kernel = cv.getStructuringElement(cv.MORPH_RECT,(3,3)) # kernel = cv.getStructuringElement(cv.MORPH_ELLIPSE,(3,3))#圆型 # kernel = cv.getStructuringElement(cv.MORPH_RECT,(1,30))#提取垂直线 # kernel = cv.getStructuringElement(cv.MORPH_RECT,(45,1))#提取水平线 dst = cv.morphologyEx(binary,cv.MORPH_OPEN,kernel)#开操作 cv.imshow("open:",dst) cv.imwrite(result_path+"y_open.jpg:",dst) def close_demo(image):#闭合操作 dst = cv.GaussianBlur(image, (5, 5), 0) # 高斯滤波 gray=cv.cvtColor(dst,cv.COLOR_BGR2GRAY) rect,binary=cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU) cv.imshow("binary:",binary) kernel = cv.getStructuringElement(cv.MORPH_RECT,(15,15)) dst = cv.morphologyEx(binary,cv.MORPH_CLOSE,kernel) cv.imshow("close:",dst) # cv.imwrite("C:\\Users\\22852\\Desktop\\opencv\\result\\dilate_handwriting.jpeg:", dst) src = cv.imread('C:\\Users\\22852\\Desktop\\opencv\\data\\y.jpg') src1 = cv.imread('C:\\Users\\22852\\Desktop\\opencv\\data\\lines.jpg') # src1 = cv.resize(src, [600, 600]) # cv.namedWindow("input image",cv.WINDOW_AUTOSIZE) cv.imshow("input image:", src) # cv.imshow("input image:", src1) open_demo(src) # close_demo(src) cv.waitKey(0) cv.destroyAllWindows()
顶帽:
def top_hat_demo(image):
gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY)
rect, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
kernel = cv.getStructuringElement(cv.MORPH_RECT,(3,3))
dst = cv.morphologyEx(gray,cv.MORPH_TOPHAT,kernel)#对灰度图
dst1 = cv.morphologyEx(binary,cv.MORPH_TOPHAT,kernel)#对二值图
cimage = np.array(gray.shape, np.uint8)
cimage = 75
dst = cv.add(dst, cimage)
cv.imshow("top_hat:",dst1)
黑帽:
ef Black_hat_demo(image):
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
rect, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
kernel = cv.getStructuringElement(cv.MORPH_RECT,(15,15))
dst = cv.morphologyEx(gray,cv.MORPH_BLACKHAT,kernel)#对灰度图
dst1 = cv.morphologyEx(binary,cv.MORPH_BLACKHAT,kernel)#对二值图
cimage = np.array(gray.shape, np.uint8)
cimage = 55
dst=cv.add(dst,cimage)
cv.imshow("Blackhat_hat:",dst1)
形态学梯度:
def Gradient_demo(image):
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
rect, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU)
kernel = cv.getStructuringElement(cv.MORPH_RECT,(3,3))
dst = cv.morphologyEx(gray,cv.MORPH_GRADIENT,kernel)#对灰度图
dst1 = cv.morphologyEx(binary,cv.MORPH_GRADIENT,kernel)#对二值图
cimage = np.array(gray.shape, np.uint8)
cimage = 55
dst=cv.add(dst,cimage)
cv.imshow("Gradient:",dst)
在该算法中,空间上相邻并且灰度值相近的像素被划分为一个区域。
分水岭算法的整个过程:
- 把梯度图像中的所有像素按照灰度值进行分类,并设定一个测地距离阈值。
- 找到灰度值最小的像素点(默认标记为灰度值最低点),让threshold从最小值开始增长,这些点为起始点。
- 水平面在增长的过程中,会碰到周围的邻域像素,测量这些像素到起始点(灰度值最低点)的测地距离,如果小于设定阈值,则将这些像素淹没,否则在这些像素上设置大坝,这样就对这些邻域像素进行了分类。
- 随着水平面越来越高,会设置更多更高的大坝,直到灰度值的最大值,所有区域都在分水岭线上相遇,这些大坝就对整个图像像素的进行了分区。
在OpenCV中,我们需要给不同区域贴上不同的标签。用大于1的整数表示我们确定为前景或对象的区域,用1表示我们确定为背景或非对象的区域,最后用0表示我们无法确定的区域。然后应用分水岭算法,我们的标记图像将被更新,更新后的标记图像的边界像素值为-1。
分水岭算法步骤:
def watershed_demo(src): # 模糊操作 blur = cv.pyrMeanShiftFiltering(src, 5, 100)#均值滤波 # blur=cv.GaussianBlur(src,(3,3),0)#高斯滤波 # 灰度、二值化图像 gray = cv.cvtColor(blur, cv.COLOR_BGR2GRAY) ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV | cv.THRESH_OTSU) cv.imshow("binary", binary) # morphology operation kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3)) mb = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel, iterations=2) #开操作迭代两次 sure_bg = cv.morphologyEx(mb, cv.MORPH_CLOSE, kernel, iterations=3) #闭操作迭代3次 cv.imshow("morphology operation", sure_bg) # distance transform dist = cv.distanceTransform(mb, cv.DIST_L2, 3) #基于L2的距离变换 dist_output = cv.normalize(dist, 0, 1, cv.NORM_MINMAX) #归一化 cv.imshow("distance_t", dist_output*50) ret, surface = cv.threshold(dist, dist.max()*0.6, 255, cv.THRESH_BINARY) cv.imshow("surface", surface) surface_fg = np.uint8(surface) #float转为int unknown = cv.subtract(sure_bg, surface_fg) ret, markers = cv.connectedComponents(surface_fg)#retval, labels print("ret =", ret) # watershed transform markers = markers +1 markers[unknown == 255] = 0 markers = cv.watershed(src, markers = markers) src[markers == -1] = [0, 0, 255] cv.imshow("result", src)
import cv2 as cv import numpy as np from PIL import Image # import pytesseract as tess def recognize_txt(image): gray = cv.cvtColor(image,cv.COLOR_BGR2GRAY) rect,binary = cv.threshold(gray,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU) cv.imshow("binary:", binary) kernel = cv.getStructuringElement(cv.MORPH_RECT,(2,1)) binary1 = cv.morphologyEx(binary,cv.MORPH_OPEN,kernel) cv.imshow("binary1:",binary1) kernel = cv.getStructuringElement(cv.MORPH_RECT, (1, 2)) binary2 = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel) cv.imshow("binary2:", binary2) cv.bitwise_not(binary2,binary2)#要变为白色背景 txt_image=Image.fromarray(binary2) text = tess.image_to_string(txt_image) print("识别结果:%s"%text) src = cv.imread("data/yzm.jpg") cv.imshow("input image:", src) recognize_txt(src) cv.waitKey(0) cv.destroyAllWindows()
需要调用opencv官方的库,比如说”haarcascade_frontalface_alt_tree.xml“
把官方库下载到本地用cv.CascadeClassifier加载
import cv2 as cv import numpy as np def face_detect(image): gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY) face_detector= cv.CascadeClassifier("C:\\Users\\22852\\Desktop\\opencv\\opencv-3.3.1\\data\\haarcascades\\haarcascade_frontalface_alt_tree.xml") faces=face_detector.detectMultiScale(gray,1.02,5) # 5:minNeighbors,越高可能检测不到人脸 #1.02:scaleFactor for x,y,w,h in faces: cv.rectangle(image,(x,y),(x+w,y+h),(0,255,255),2) cv.imshow("result:",image) src = cv.imread('C:\\Users\\22852\\Desktop\\opencv\\data\\face.jpg') cv.namedWindow("input image:",cv.WINDOW_AUTOSIZE) cv.imshow("input image:", src) face_detect(src)
也可以直接调摄像头进行视频检测~
import cv2 as cv import numpy as np def face_detect(image): gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY) face_detector= cv.CascadeClassifier("C:\\Users\\22852\\Desktop\\opencv\\opencv-3.3.1\\data\\haarcascades\\haarcascade_frontalface_alt_tree.xml") faces=face_detector.detectMultiScale(gray,1.02,5) # 5:minNeighbors,越高可能检测不到人脸 #1.02:scaleFactor for x,y,w,h in faces: cv.rectangle(image,(x,y),(x+w,y+h),(0,255,255),2) cv.imshow("result:",image) capture = cv.VideoCapture(0) while(True): ret,frame = capture.read() frame=cv.flip(frame,1) face_detect(frame) c=cv.waitKey(10) if c==27: #ESC break
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。