给一张图片和模板图片(如下图),需要用传统机器视觉的方法来提取他们不一样的特征(也就是划痕部分),并把划痕转为二值化
1.1 才开始使用基于灰度的方法:
因为划痕和旁边背景颜色比较接近,绘制出的灰度直方图变化不大,调了很久阈值也不能分出划痕部分,效果如下:
1.2 后来直接使用图像相减,RGB和Gray分别图像相减结果得到如下:
解决方案:
应该是没有配准而相减有边框的,最终决定配准后,图像相减
查阅资料文献后,大致思路如下:
1. RGB—> 灰度图
2. 去噪滤波,图像增强等一系列预处理操作
3. 提特征点(ORB)并进行图像配准
4. 配准后进行二值化
5. 图像相减操作(ImageChops.difference)
# 1. 转为灰度图
target = cv2.imread("2368_data.png")
gray_target=cv2.cvtColor(target, cv2.COLOR_BGR2GRAY)
template = cv2.imread("2368_model.png")
gray_template=cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
2. 去噪滤波 预处理操作
# 去噪滤波 预处理
target_gauss = cv2.GaussianBlur(gray_target,(3, 3),1,1)
template_gauss = cv2.GaussianBlur(gray_template,(3, 3),1,1)
# plt转为cv
target_gauss =Image.fromarray(target_gauss) # np array
template_gauss =Image.fromarray(template_gauss) # np array
# 亮度增强
bright= 0.9
bright_target=ImageEnhance.Brightness(target_gauss).enhance(bright)
bright_template=ImageEnhance.Brightness(template_gauss).enhance(bright)
#色度增强
color = 1.2
colored_target = ImageEnhance.Color(bright_target).enhance(color)
colored_template = ImageEnhance.Color(bright_template).enhance(color)
# 对比度增强
contrast =1.1
contrasted_target = ImageEnhance.Contrast(colored_target).enhance(contrast)
contrasted_template = ImageEnhance.Contrast(colored_template).enhance(contrast)
# 锐度增强
sharpness = 18.0
shaped_target= ImageEnhance.Sharpness(contrasted_target).enhance(sharpness)
shaped_template= ImageEnhance.Sharpness(contrasted_template).enhance(sharpness)
plt.subplot(121), plt.imshow(shaped_target, cmap='gray')
plt.title('shaped_target'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(shaped_template, cmap='gray')
plt.title('shaped_template'), plt.xticks([]), plt.yticks([])
plt.show()
1.只做高斯去噪,不做亮度,锐化等预处理后的图片:
2.不进行高斯去噪,只进行预处理的图:
灰度后的图片会产生很多噪点,因此进行去噪滤波还是有一定效果的。
去噪
3.做完高斯去噪以及一系列亮度,锐化预处理后的图片:
(具体参数还没有详细调,只是先按这个值先设置)
参考资料《mage Alignment (Feature Based) using OpenCV (C++/Python)》
核心思想:
在一个图像中检测到一组特征点,并与另一张图像中的特征点相匹配。然后根据这些匹配的特征点计算出一个转换规则,从而将一个图像映射到另一个图像上。
主要应用就是扫描软件,合成全景图片等。
图像对齐技术的核心是一种维数3X3的单应性矩阵(Homography )
图像配准步骤:
- 读取图片
- 检测特征点:为两张图检测ORB特征点。为了计算单应性矩阵4个就够了,但是一般会检测到成百上千的特征点。可以使用参数MAX_FEATURES来控制检测的特征点的数量。检测特征点并计算描述子的函数是detectAndCompute。
- 特征匹配:找到两图中匹配的特征点,并按照匹配度排列,保留最匹配的一小部分。然后把匹配的特征点画出来并保存图片到磁盘。我们使用Hamming来度量两个特征点描述子的相似度。下图中把匹配的特征点用线连起来了。注意,有很多错误匹配的特征点,所以下一步要用一个健壮的算法来计算单应性矩阵。
- 计算单应性矩阵:上一步产生的匹配的特征点不是100%正确的,就算只有20~30%的匹配是正确的也不罕见。findHomography函数使用一种被称为随机抽样一致算法(Random Sample Consensus )的技术在大量匹配错误的情况下计算单应性矩阵。
- 扭转图片(Warping image):有了精确的单应性矩阵,就可以把一张图片的所有像素映射到另一个图片。warpPerspective函数用来完成这个功能。
如何把两张图像中的特征点匹配起来呢?
SIFT一般的可以使用K近邻(KNN)算法。K近邻算法求取在空间中距离最近的K个数据点,并将这些数据点归为一类。在进行特征点匹配时,一般使用KNN算法找到最近邻的两个数据点,如果最接近和次接近的比值大于一个既定的值,那么我们保留这个最接近的值,认为它和其匹配的点为good match(有Lowe在SIFT论文中提出)
单应性矩阵Homography Matrix
找到特征点并匹配起来后,如何让两张图片对齐呢?
这就用到了单应性矩阵了。Homography这个词由Homo和graphy,Homo意为同一,graphy意为图像,也就是同一个东西产生的图像。不同视角的图像上的点具有如下关系:
其中[x1 y1 1]和[x2 y2 1]分别表示对应像素的齐次坐标。单应性矩阵就是下面这个矩阵:
可以看到,单应性矩阵有八个参数,如果要解这八个参数的话,需要八个方程,由于每一个对应的像素点可以产生2个方程(x一个,y一个),那么总共只需要四个像素点就能解出这个单应性矩阵。
那么应该选择哪四个点来计算Homography matrix呢?
RANSAC算法巧妙的解决了这一问题。
说道估算模型的算法,很容易想到最小二乘法。最小二乘法在数据误差比较小的情况下是可以的,但是针对噪声很大的数据集的时候,容易出问题,我们可以通过下面的例子来说明
很明显,我们的数据应该是一条由左下到右上的一条线,但是由于离群数据太多(左上和右下区域),如果用最小二乘法的话,就无法准确的找到我们期望的模型(因为最小二乘法无法剔除误差很大的点,一视同仁的将所有的点都用于模型的计算)。RANSAC(Random Sample Consensus)算法的不同之处就在于,它能够有效的去除误差很大的点,并且这些点不计入模型的计算之中。
所以,在得到了众多的匹配点以后,使用RANSAC算法,每次从中筛选四个随机的点,然后求得H矩阵,不断的迭代,直到求得最优的H矩阵为止。所以在前面使用cv2.findHomography方法时,参数cv2.RANSAC表明使用RANSAC算法来筛选关键点
3.2 代码部分- 读取图片并创建ORB
import cv2 as cv
image1 = cv.imread('1.png')
image2 = cv.imread('2.png')
# 初始化ORB
orb = cv.ORB_create()
- 寻找关键点和描述子
# 寻找关键点 kp1 = orb.detect(img1) kp2 = orb.detect(img2) # 计算描述符 kp1,des1=orb.detectAndCompute(img1,None) # 计算哪张图片的用哪张图片的关键点。 kp2,des2=orb.detectAndCompute(img2,None)
找到了关键点可以画出关键点看一看:
# 画出关键点
outimg1 = cv.drawKeypoints(img1, keypoints=kp1, outImage=None)
outimg2 = cv.drawKeypoints(img2, keypoints=kp2, outImage=None)
# 这里是把两张图片在同一个窗口中显示。
import numpy as np
outimg3 = np.hstack([outimg1, outimg2])
cv.imshow("Key Points", outimg3)
cv.waitKey(0)
- 关键点匹配
有了关键点和描述子,我们就要对这些点进行匹配。这里我们用的是Brute-Force匹配器,它获取第一组中一个特征的描述符,并通过一些距离计算与第二组中的所有其他特征匹配,最接近的一个被返回。
# 初始化 BFMatcher bf = cv.BFMatcher(cv.NORM_HAMMING) # 对描述子进行匹配 matches = bf.match(des1, des2)
- 对匹配点进行筛选并画出匹配图
good_match=sorted(mathces,key=lambda x:x.distance) #据距离来排序
result= cv2.drawMatches(gray_target,kp1, gray_template,kp2,good_match,outImg=None) #画出匹配关系
cv2.namedWindow('Match Result',cv2.WINDOW_NORMAL)
cv2.imshow("Match Result", result)
cv2.waitKey(0)
- 计算单应性矩阵 (findHomography函数)
首先找出target和template中的特征点,然后找到较好的匹配点对good_match(判断good_match是否大于4,至少4个匹配点才能构建矩阵),最后通过warpPerspective方法对图像target进行投影映射。
if len(goodMatch) > 4:
ptsA= np.float32([kp1[m.queryIdx].pt for m in goodMatch]).reshape(-1, 1, 2)
ptsB = np.float32([kp2[m.trainIdx].pt for m in goodMatch]).reshape(-1, 1, 2)
ransacReprojThreshold = 4
H, status =cv2.findHomography(ptsA,ptsB,cv2.RANSAC,ransacReprojThreshold);
imgOut = cv2.warpPerspective(img2, H, (img1.shape[1],img1.shape[0]),flags=cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP)
cv2.warpPerspective(img,H,(img1.shape[1],img1.shape[0]),cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP)
第一个参数为需要投影的图像(img2)
第二个参数为单应性矩阵(H)
第三个参数为所得图像的矩阵大小((img1.shape[1],img1.shape[0]) )
最后的参数cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP,为插值时使用的插值方法INTER_LINEAR,cv2.WARP_INVERSE_MAP则将M设置为dst—>src的方向变换。
遇到的问题:
kp1求出来的特征点只有两个,构建单应性矩阵最少需要4个,故一直报错
后来查询到ORB产生的特征点在点特征提取算法中最少(详细特征提取算法比对参考Related-8),因此换成了KAZE检测器,产生的特征点很明显增多,匹配显示结果如下:
最终的透视变换结果如下:
emmmm…后来发现自己可能不需要透视变换,只需要简单的平移对齐就好,于是改成仿射变换的矩阵
Tips 1. plt 与opencv相互转换
plt转为opencv
from PIL import Image
import numpy as np
import cv2
img=Image.open(path)
#PIL转ndarray
img=np.array(img)
img=img[:,:,(2,1,0))]
#show
cv2.imshow('img',img)
cv2.waitKey(0)
#write
cv2.imwrite(path,img)
opencv 转为 plt
img=Image.fromarray(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))) #img=Image.fromarray(img) plt.imshow(img) #show plt.show() #save、dpi为分辨率 plt.savefig(path,dpi=100)2.仿射变换和透视变换
简单写一下:
仿射变换:线性变换+平移,二维图像---->二维图像
透射变换:线性变换+平移,二维图像---->投影到三维平面----->转为二维坐标,因此它是空间上的调整,比如图片弯曲
区别是:仿射变换是(2x3)的变换矩阵,透射变换是(3x3)的变换矩阵
Related1.Image Alignment (ECC) in OpenCV ( C++ / Python )
2.OpenCV快速入门——图像预处理(必看)
3.opencv+python实现图像匹配----模板匹配、特征点匹配
4.Nice!!!Python进行SIFT图像对准
5.图像对齐(图像配准)方法记录
6.OpenCV-Python Feature2D 特征点检测(含SIFT/SURF/ORB/KAZE/FAST/BRISK/AKAZE)
7.OpenCV-Python ORB特征匹配(实践篇)
8.报错等问题:
第6章 特征检测、匹配与搜索 个人笔记
9.基于机器视觉的PCB缺陷检测与分类识别
10.OPENCV特征点提取算法对比



