opencv之直方图均衡--边缘检测--模板匹配--霍夫线变换

直方图均衡化

yes,听名字直方图均衡化,直方图是对图片像素的统计,均衡化就是平均一下,什么意思呢,比如一张图片白的很白,黑的很黑,这样就不好,把峰值往下平摊,都得到一些值,这样可以提高对比度,对于一些高亮或者暗的环境处理好。

看代码 

import  cv2 as cv
import  math
import numpy as np
import  matplotlib.pyplot as plt

path=r"F:\testp.png"
img=cv.imread(path,0)
rows,cols=img.shape[:2]
cv.imshow("1",img)


zhifang=cv.equalizeHist(img)


cv.imshow("2",zhifang)



cv.waitKey(0)



cv.destroyAllWindows()

 上面的直方图均衡有时候将细节忽略掉,所以出来了自适应直方图均衡化

 它把图片分成一个个小块,进行直方图均衡化,并且会设置上限阈值来分去比较大的像素值分给其他bins中,也就是增加对比度,但不是很夸张。

import  cv2 as cv
import  math
import numpy as np
import  matplotlib.pyplot as plt

path=r"F:\testp.png"
img=cv.imread(path,0)
rows,cols=img.shape[:2]
cv.imshow("1",img)


cl=cv.createCLAHE(clipLimit=2.0,tileGridSize=(8,8))
cll=cl.apply(img)

cv.imshow("2",cll)

cv.waitKey(0)



cv.destroyAllWindows()

边沿检测

分为基于搜索导数的最大值和基于二阶导数的过零点值。

sobel算子 利用导数最大值来寻找

[-1,0,+1],[-2,0,2],[-1,0,+1]是水平变化做卷积

[-1,-2,-1],[0,0,0],[1,2,1]是垂直变化做卷积

结合两个结果的平方和的开根号,统计极大值位置也就是边缘。

内核为3的时候,sobel有缺陷,用schar算子弥补,但schar只使用在内核3的卷积,ksize为1,3,5,7

import  cv2 as cv
import  math
import numpy as np
import  matplotlib.pyplot as plt

path=r"F:\testp.png"
img=cv.imread(path,0)
rows,cols=img.shape[:2]
cv.imshow("1",img)

x1=cv.Sobel(img,cv.CV_16S,1,0)
y1=cv.Sobel(img,cv.CV_16S,0,1)

xx1=cv.convertScaleAbs(x1)
yy1=cv.convertScaleAbs(y1)

r1=cv.addWeighted(xx1,0.5,yy1,0.5,0)


#下面是schar算子
x2=cv.Sobel(img,cv.CV_16S,1,0,ksize=-1)
y2=cv.Sobel(img,cv.CV_16S,0,1,ksize=-1)

xx2=cv.convertScaleAbs(x2)
yy2=cv.convertScaleAbs(y2)

r2=cv.addWeighted(xx2,0.5,yy2,0.5,0)




cv.imshow("2",r1)
cv.imshow("3",r2)





cv.waitKey(0)



cv.destroyAllWindows()

拉普拉斯算子(过零点二阶导数)

import  cv2 as cv
import  math
import numpy as np
import  matplotlib.pyplot as plt

path=r"F:\testp.png"
img=cv.imread(path,0)
rows,cols=img.shape[:2]
cv.imshow("1",img)


lab=cv.Laplacian(img,cv.CV_16S,ksize=5)
s=cv.convertScaleAbs(lab)

cv.imshow("s",s)





cv.waitKey(0)



cv.destroyAllWindows()

这里也需要用到类型转换,我还发现通过改变ksize的大小,效果也明显不同,我调大了ksize的值会让边界线更粗厚

一种牛逼的算子 --- canny算子(最优算法)

 这边缘检测分为四步进行

第一步:噪声去除

用5x5高斯滤波器先滤去噪点

第二步:和sobel相近,去计算梯度和一阶导数,梯度有值和方向。

第三步:再次扫描整幅图像去除非边界点,看每个点梯度是不是周围方向最大的,如果是就保留,不是则抑制成细边

最后一步:滞后阈值,设置两个阈值,梯度高于这个才是真的边界,在中间的若和真的边界相连也保留,若不相邻则是假的边界去除。

import  cv2 as cv
import  math
import numpy as np
import  matplotlib.pyplot as plt

path=r"F:\testp.png"
img=cv.imread(path,0)
rows,cols=img.shape[:2]
cv.imshow("1",img)


s=cv.Canny(img,0,20)
cv.imshow("s",s)





cv.waitKey(0)



cv.destroyAllWindows()

 经过实验,确实效果是最佳的!边界平滑并且美丽

模板匹配

在openmv也学了模板匹配,就是先存一个照片当模板,然后去找图片中和模板最相似的。

原理是什么呢?其实是模板这个照片在原图像的滑动,匹配每个像素点,从左上一个一个像素点滑动到右下,把相似结果保存在矩阵中,获取最大值位置后,那么该位置是最匹配的,对应的就是模板的顶点,长宽和模板大小一样的。有三种匹配方式

cv.tm.sqdiff     cv.tm.ccorr       cv.tm.ccoeff   第一个是越小越好,后两个是越大越好

import  cv2 as cv
import  math
import numpy as np
import  matplotlib.pyplot as plt

path=r"F:\chenhao.jpg"
img=cv.imread(path)
rows,cols=img.shape[:2]
cv.imshow("1",img)


path1=r"F:\yanjing.png"
yanjing=cv.imread(path1)


h,w,l=yanjing.shape
r=cv.matchTemplate(img,yanjing,cv.TM_SQDIFF)
min_val,max_val,min_lo,max_lo=cv.minMaxLoc(r)

cv.rectangle(img,min_lo,(min_lo[0]+w,min_lo[1]+h),(0,0,255),2)
cv.imshow("2",img)

cv.imshow("3",yanjing)
cv.waitKey(0)



cv.destroyAllWindows()

经过实验,不同放大找出来的位置有些不同,说明不同方法找出来的效果是很不一样的感觉,我用后两种方法找不出对应的模板,换成了第一种方法找到了模板.

cv.rectangle(img,m[2],(m[2][0]+w,m[2][1]+h),(0,0,255),2)这样也是行的通的

霍夫变换

首先是霍夫线变换

创建一个rho和theta的累加器二维数组,行数应与对角线长度相同,取一个点遍历所有theta的值的rho值,在累加器上加1,搜索累加器中最大值,对应的rho和theta就是那条直线。

在进行检测之前必须让图像变成二值化,或者先进行canny检测。

import  cv2 as cv
import  math
import numpy as np
import  matplotlib.pyplot as plt

path=r"F:\kaibi.png"
img=cv.imread(path)
rows,cols=img.shape[:2]
cv.imshow("1",img)

edge=cv.Canny(img,80,100)
cv.imshow("2",edge)

lines=cv.HoughLines(edge,0.1,np.pi/180,80)
for line in lines:
    xinxi=line[0]
    a=np.cos(xinxi[1])
    b=np.sin(xinxi[1])
    x0=a*xinxi[0]
    y0=b*xinxi[0]
    x1 = int(x0 + 1000 * (-b))
    x2 = int(x0 - 1000 * (-b))
    y1 = int(y0 + 1000 * (-a))
    y2 = int(y0 - 1000 * (-a))
    cv.line(img,(x1,y1),(x2,y2),(0,0,255))
cv.imshow("3",img)

print(lines)
cv.waitKey(0)



cv.destroyAllWindows()

这里看一下lines具体是什么:

[[[322.95        1.5707964]]

 [[ 25.95        1.5707964]]

 [[250.95        1.5707964]]

 [[526.95        0.       ]]

 [[  4.9500003   0.       ]]

 [[ 97.950005    1.5707964]]

 [[291.95        0.       ]]

 [[212.95        0.       ]]

 [[ 76.950005    0.       ]]

 [[382.95        0.       ]]

 [[177.95        1.5707964]]

 [[161.95        1.5707964]]

 [[160.95        1.5707964]]

 [[178.95        1.5707964]]]

是检测到的rho和theta的值,xinxi[0]是rho,xinxi[1]是theta

这里为什莫xinxi等于line[0]呢?这是因为for 循环只能去一个括号,也就是line等于[[322.95        1.5707964]],这样的话line[0]才是里面的两个值。

还有0.1 np.pi/180是rho和theta的精度,80是阈值,大于这个值才会认为是直线,可以调整这个值来忽略短一点的直线。

 

你可能感兴趣的:(opencv,opencv,python,人工智能)