Opencv 单应性不产生所需的转换
Opencv homography does not produce the required tranformation
我正在尝试沿对象的边缘变换图像(这里的对象是书)。使用精明的边缘检测,我正在检测边缘,并根据像素值从得分矩阵中选择一个随机的 4 个位于边缘的坐标进行转换。但转型并不像它想象的那样。 problem/Where 我错过了什么?
首先我切出了一部分图像。然后应用Canny边缘检测,根据自己的情况随机选取4个边缘坐标点为:
我的原图是:
为了实验,我根据自己的需要切出了:
这张图片的大小(61,160)
现在需要对上图进行变换,使书的边缘与横轴平行
img = cv2.imread('download1.jpg',0)
edges = cv2.Canny(img,100,200)
print(img.shape)
plt.show()
plt.imshow(img,cmap='gray')
l=[]
y_list=[]
k=1
for i in range (0,img.shape[0]):
for j in range (0,img.shape[1]):
if (edges[i][j]==255) and k<=4 and i>31 and j not in y_list:
l.append([j,i])
y_list.append(j)
k+=1
break
得到边缘检测图像为:
l列表的内容是
[[49 32]
[44 33]
[40 34]
[36 35]]
然后将list lt给出的目的地点设置为:
[[49 61]
[44 60]
[40 61]
[36 60]]
然后找出单应性矩阵并用它来找出扭曲透视为:
h, status = cv2.findHomography(l,lt)
im_out = cv2.warpPerspective(img, h, (img.shape[1],img.shape[0]))
但它没有产生所需的结果!得到的结果输出图像为:
我遇到了类似的问题,这就是我解决它的方法(实际上与您的方法非常相似),只是我使用了 get rotation matrix 而不是 homografy:
- 阅读图片
- 边缘检测器
hough line 获取所有线(在特定区间内具有倾斜度)
lines = cv.HoughLinesP(img, 1, np.pi/180, 100, minLineLength=100, maxLineGap=10)
获取线的平均倾角,因为在我的例子中我有很多平行线用作
参考文献,这样我就能得到更好的结果
for line in lines:
x1,y1,x2,y2 = line[0]
if (x2-x1) != 0:
angle = math.atan((float(y2-y1))/float((x2-x1))) * 180 / math.pi
else:
angle = 90
#you can skip this test if you have no info about the lines you re looking for
#in this case offset_angle is = 0
if min_angle_threshold <= angle <= max_angle_threshold:
tot_angle = tot_angle + angle
cnt = cnt + 1
average_angle = (tot_angle / cnt) - offset_angle
应用counter-rotation
center = your rotation center - probably the center of the image
rotation_matrix = cv.getRotationMatrix2D(center, angle, 1.0)
height, width = img.shape
rotated_image = cv.warpAffine(img, rotation_matrix, (width, height))
#do whatever you want, then rotate image back
counter_rotation_matrix = cv.getRotationMatrix2D(center, -angle, 1.0)
original_image = cv.warpAffine( rotated_image, counter_rotation_matrix, (width, height))
编辑:在此处查看完整示例:
import math
import cv2 as cv
img = cv.imread('C:\temp\test_3.jpg',0)
edges = cv.Canny(img,100,200)
lines = cv.HoughLinesP(edges[0:50,:], 1, np.pi/180, 50, minLineLength=10, maxLineGap=10)
tot_angle = 0
cnt = 0
for line in lines:
x1,y1,x2,y2 = line[0]
if (x2-x1) != 0:
angle = math.atan((float(y2-y1))/float((x2-x1))) * 180 / math.pi
else:
angle = 90
if -30 <= angle <= 30:
tot_angle = tot_angle + angle
cnt = cnt + 1
average_angle = (tot_angle / cnt)
h,w = img.shape[:2]
center = w/2, h/2
rotation_matrix = cv.getRotationMatrix2D(center, average_angle, 1.0)
height, width = img.shape
rotated_image = cv.warpAffine(img, rotation_matrix, (width, height))
cv.imshow("roto", rotated_image)
#do all your stuff here, add text and whatever
#...
#...
counter_rotation_matrix = cv.getRotationMatrix2D(center, -average_angle, 1.0)
original_image = cv.warpAffine( rotated_image, counter_rotation_matrix, (width, height))
cv.imshow("orig", original_image)
旋转
]1
counter_rotated
]2
编辑:
如果你想应用单应性(不同于简单的旋转,因为它还应用了透视变换),请在代码下方使其工作:
#very basic example, similar to your code with fixed terms
l = np.array([(11,32),(43,215),(142,1),(205,174)])
lt = np.array([(43,32),(43,215),(205,32),(205,215)])
h, status = cv.findHomography(l,lt)
im_out = cv.warpPerspective(img, h, (img.shape[1],img.shape[0]))
以编程方式进行
- 对于 "l" :也只需使用 houghlines 并找到 4 个角,
然后添加它们
for "lt": 为所有 4 个点找到一个 "destination",例如使用底角作为参考
lines = cv.HoughLinesP(edges, 1, np.pi/180, 100, minLineLength=150, maxLineGap=5)
l = []
for line in lines:
x1,y1,x2,y2 = line[0]
if (x2-x1) != 0:
angle = math.atan((float(y2-y1))/float((x2-x1))) * 180 / math.pi
else:
angle = 90
# consider only vertical edges
if 60 <= angle:
l.append((x1,y1))
l.append((x2,y2))
x_values.append(max(x1,x2))
if len(y_values) == 0:
y_values.append(y1)
y_values.append(y2)
l = np.array(l)
lt = np.array([(x_values[0],y_values[0]),(x_values[0],y_values[1]),(x_values[1],y_values[0]),(x_values[1],y_values[1])])
然后像上面那样调用 findhomography
希望它足够清楚!
3
我正在尝试沿对象的边缘变换图像(这里的对象是书)。使用精明的边缘检测,我正在检测边缘,并根据像素值从得分矩阵中选择一个随机的 4 个位于边缘的坐标进行转换。但转型并不像它想象的那样。 problem/Where 我错过了什么?
首先我切出了一部分图像。然后应用Canny边缘检测,根据自己的情况随机选取4个边缘坐标点为: 我的原图是:
为了实验,我根据自己的需要切出了:
这张图片的大小(61,160)
现在需要对上图进行变换,使书的边缘与横轴平行
img = cv2.imread('download1.jpg',0)
edges = cv2.Canny(img,100,200)
print(img.shape)
plt.show()
plt.imshow(img,cmap='gray')
l=[]
y_list=[]
k=1
for i in range (0,img.shape[0]):
for j in range (0,img.shape[1]):
if (edges[i][j]==255) and k<=4 and i>31 and j not in y_list:
l.append([j,i])
y_list.append(j)
k+=1
break
得到边缘检测图像为:
l列表的内容是
[[49 32]
[44 33]
[40 34]
[36 35]]
然后将list lt给出的目的地点设置为:
[[49 61]
[44 60]
[40 61]
[36 60]]
然后找出单应性矩阵并用它来找出扭曲透视为:
h, status = cv2.findHomography(l,lt)
im_out = cv2.warpPerspective(img, h, (img.shape[1],img.shape[0]))
但它没有产生所需的结果!得到的结果输出图像为:
我遇到了类似的问题,这就是我解决它的方法(实际上与您的方法非常相似),只是我使用了 get rotation matrix 而不是 homografy:
- 阅读图片
- 边缘检测器
hough line 获取所有线(在特定区间内具有倾斜度)
lines = cv.HoughLinesP(img, 1, np.pi/180, 100, minLineLength=100, maxLineGap=10)
获取线的平均倾角,因为在我的例子中我有很多平行线用作 参考文献,这样我就能得到更好的结果
for line in lines: x1,y1,x2,y2 = line[0] if (x2-x1) != 0: angle = math.atan((float(y2-y1))/float((x2-x1))) * 180 / math.pi else: angle = 90 #you can skip this test if you have no info about the lines you re looking for #in this case offset_angle is = 0 if min_angle_threshold <= angle <= max_angle_threshold: tot_angle = tot_angle + angle cnt = cnt + 1 average_angle = (tot_angle / cnt) - offset_angle
应用counter-rotation
center = your rotation center - probably the center of the image rotation_matrix = cv.getRotationMatrix2D(center, angle, 1.0) height, width = img.shape rotated_image = cv.warpAffine(img, rotation_matrix, (width, height)) #do whatever you want, then rotate image back counter_rotation_matrix = cv.getRotationMatrix2D(center, -angle, 1.0) original_image = cv.warpAffine( rotated_image, counter_rotation_matrix, (width, height))
编辑:在此处查看完整示例:
import math
import cv2 as cv
img = cv.imread('C:\temp\test_3.jpg',0)
edges = cv.Canny(img,100,200)
lines = cv.HoughLinesP(edges[0:50,:], 1, np.pi/180, 50, minLineLength=10, maxLineGap=10)
tot_angle = 0
cnt = 0
for line in lines:
x1,y1,x2,y2 = line[0]
if (x2-x1) != 0:
angle = math.atan((float(y2-y1))/float((x2-x1))) * 180 / math.pi
else:
angle = 90
if -30 <= angle <= 30:
tot_angle = tot_angle + angle
cnt = cnt + 1
average_angle = (tot_angle / cnt)
h,w = img.shape[:2]
center = w/2, h/2
rotation_matrix = cv.getRotationMatrix2D(center, average_angle, 1.0)
height, width = img.shape
rotated_image = cv.warpAffine(img, rotation_matrix, (width, height))
cv.imshow("roto", rotated_image)
#do all your stuff here, add text and whatever
#...
#...
counter_rotation_matrix = cv.getRotationMatrix2D(center, -average_angle, 1.0)
original_image = cv.warpAffine( rotated_image, counter_rotation_matrix, (width, height))
cv.imshow("orig", original_image)
旋转
counter_rotated
编辑:
如果你想应用单应性(不同于简单的旋转,因为它还应用了透视变换),请在代码下方使其工作:
#very basic example, similar to your code with fixed terms
l = np.array([(11,32),(43,215),(142,1),(205,174)])
lt = np.array([(43,32),(43,215),(205,32),(205,215)])
h, status = cv.findHomography(l,lt)
im_out = cv.warpPerspective(img, h, (img.shape[1],img.shape[0]))
以编程方式进行 - 对于 "l" :也只需使用 houghlines 并找到 4 个角, 然后添加它们
for "lt": 为所有 4 个点找到一个 "destination",例如使用底角作为参考
lines = cv.HoughLinesP(edges, 1, np.pi/180, 100, minLineLength=150, maxLineGap=5) l = [] for line in lines: x1,y1,x2,y2 = line[0] if (x2-x1) != 0: angle = math.atan((float(y2-y1))/float((x2-x1))) * 180 / math.pi else: angle = 90 # consider only vertical edges if 60 <= angle: l.append((x1,y1)) l.append((x2,y2)) x_values.append(max(x1,x2)) if len(y_values) == 0: y_values.append(y1) y_values.append(y2) l = np.array(l) lt = np.array([(x_values[0],y_values[0]),(x_values[0],y_values[1]),(x_values[1],y_values[0]),(x_values[1],y_values[1])])
然后像上面那样调用 findhomography 希望它足够清楚!