rar*_*son 5 python opencv image-processing image-rotation feature-detection
我正在进行一个项目,以自动旋转流体实验的显微镜图像堆栈,以便它们与微流控芯片的CAD模板图像对齐。我正在使用Python中的OpenCV软件包进行图像处理。必须具有正确的旋转方向,以便可以正确遮盖图像以进行分析。我们的芯片具有在每个帧中都可见的充满荧光染料的标记。模板和示例图像如下所示(模板可以缩放到任意大小,但是图像的相关区域通常约为100x100像素左右):
我无法将图像旋转对齐到CAD模板。通常,CAD模板与图像之间的未对准小于几度,这仍然足以干扰分析,因此即使它相对较小,我也需要能够测量旋转差异。
在线以下示例我正在使用以下过程:
这是我的代码示例(部分从此处借来):
import numpy as np
import cv2
import matplotlib.pyplot as plt
MAX_FEATURES = 500
GOOD_MATCH_PERCENT = 0.5
def alignImages(im1, im2,returnpoints=False):
# Detect ORB features and compute descriptors.
size1 = int(0.1*(np.mean(np.shape(im1))))
size2 = int(0.1*(np.mean(np.shape(im2))))
orb1 = cv2.ORB_create(MAX_FEATURES,edgeThreshold=size1,patchSize=size1)
orb2 = cv2.ORB_create(MAX_FEATURES,edgeThreshold=size2,patchSize=size2)
keypoints1, descriptors1 = orb1.detectAndCompute(im1, None)
keypoints2, descriptors2 = orb2.detectAndCompute(im2, None)
matcher = cv2.BFMatcher(cv2.NORM_HAMMING,crossCheck=True)
matches = matcher.match(descriptors1,descriptors2)
# Sort matches by score
matches.sort(key=lambda x: x.distance, reverse=False)
# Remove not so good matches
numGoodMatches = int(len(matches) * GOOD_MATCH_PERCENT)
matches = matches[:numGoodMatches]
# Draw top matches
imMatches = cv2.drawMatches(im1, keypoints1, im2, keypoints2, matches, None)
cv2.imwrite("matches.jpg", imMatches)
# Extract location of good matches
points1 = np.zeros((len(matches), 2), dtype=np.float32)
points2 = np.zeros((len(matches), 2), dtype=np.float32)
for i, match in enumerate(matches):
points1[i, :] = keypoints1[match.queryIdx].pt
points2[i, :] = keypoints2[match.trainIdx].pt
# Find homography
M, inliers = cv2.estimateAffinePartial2D(points1,points2)
height, width = im2.shape
im1Reg = cv2.warpAffine(im1,M,(width,height))
return im1Reg, M
Run Code Online (Sandbox Code Playgroud)
if __name__ == "__main__":
test_template = cv2.cvtColor(cv2.imread("test_CAD_cropped.png"),cv2.COLOR_RGB2GRAY)
test_image = cv2.cvtColor(cv2.imread("test_CAD_cropped.png"),cv2.COLOR_RGB2GRAY)
fx = fy = 88/923
test_image_big = cv2.resize(test_image,(0,0),fx=1/fx,fy=1/fy,interpolation=cv2.INTER_CUBIC)
ret, imRef_t = cv2.threshold(test_template,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
ret, test_big_t = cv2.threshold(test_image_big,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
imReg, M = alignImages(test_big_t,imRef_t)
fig, ax = plt.subplots(nrows=2,ncols=2,figsize=(8,8))
ax[1,0].imshow(imReg)
ax[1,0].set_title("Warped Image")
ax[0,0].imshow(imRef_t)
ax[0,0].set_title("Template")
ax[0,1].imshow(test_big_t)
ax[0,1].set_title("Thresholded Image")
ax[1,1].imshow(imRef_t - imReg)
ax[1,1].set_title("Diff")
plt.show()
Run Code Online (Sandbox Code Playgroud)
在此示例中,我得到以下不良转换,因为只有三个匹配的关键点并且它们都不正确:
我发现不管我的关键点/描述符参数如何,我倾向于获得的“好”功能太少。我可以做些什么来更好地对图像进行预处理,从而更可靠地获得良好的功能,或者有更好的方法将图像与不涉及关键点匹配的模板对齐?该实验的特定应用意味着我无法使用获得专利的关键点提取器/描述符,例如SURF和SIFT。
仅基于旋转、平移和缩放对齐两个图像的好方法是傅立叶梅林变换。
import PyDIP as dip
# load data
image = dip.ImageRead('image.png')
template = dip.ImageRead('template.png')
template = template.TensorElement(0) # this one is RGB, take any one channel
# pad the two images with zeros so they have equal sizes
sz = [max(image.Size(0), template.Size(0)), max(image.Size(1), template.Size(1))]
image = image.Pad(sz)
template = template.Pad(sz)
# match
res = dip.FourierMellinMatch2D(template, image)
# display
dip.JoinChannels((template,res,res)).Show()
Run Code Online (Sandbox Code Playgroud)
但是,还有许多其他方法。这里的关键是模板和图像都非常简单,而且非常相似。这使得注册非常容易。
例如,假设您对模板进行了适当的缩放(我认为这应该不是问题),您需要做的就是找到旋转和平移。您可以强制旋转,只需将图像旋转一组小角度,并将每个结果与模板匹配(互相关)。具有最佳匹配(最大互相关值)的那个具有适当的旋转。如果您需要非常精确的旋转估计,您可以做第二组角度接近第一组中的最佳选择。
互相关便宜且易于计算,并导致高精度的平移估计(傅立叶梅林方法广泛使用它)。不要只是在互相关输出中找到具有最大值的像素,您可以将抛物线拟合到该抛物线周围的少数像素并使用拟合抛物线的最大值的位置。这导致翻译的亚像素估计。
归档时间: |
|
查看次数: |
79 次 |
最近记录: |