我们设计出了二维码的编码和解码,但要进行拍摄的时候,就必须对拍摄的图片进行定位和裁剪,以达到更好的识别效果。
一、二维码的定位
参考这篇博客的内容,我们对二维码定位点识别
python+opencv实现二维码定位(一)
其思路的核心有几点:首先利用opencv的cv2.cvtColor()以及cv2.threshold()对图片进行处理。而后cv2.findContours()进行进一步的轮廓提取。
'''检测轮廓'''
def detect(image):
width,height=image.shape[:2][::-1]
img_gray=cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)#转灰度图
retval,binary=cv2.threshold(img_gray,0,255,cv2.THRESH_OTSU+cv2.THRESH_BINARY_INV)#二值化处理
contours,hierarchy=cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)#等级树结构轮廓
#cv2.drawContours(img,contours,-1,(0,0,255),3)
#cv2.imshow("img",image)
#cv2.waitKey()
return contours,hierarchy
接下来是对识别到的轮廓进行处理,判断是否满足1:1:3:1:1的二维码定位点设计比例。
'''轮廓比例 边占比7:5'''
def get_scale1(contours,i,j):
#外轮廓和子轮廓比例 1:1:3:1:1
area1=cv2.contourArea(contours[i])#轮廓面积1
area2=cv2.contourArea(contours[j])#轮廓面积2
if area2==0:#无子轮廓
return False
ratio = area1*1.0 / area2
if abs(ratio-49.0/25): # 7/5
return True
return False
'''轮廓比例 边占比5:3'''
def get_scale2(contours,i,j):
#子轮廓和子子轮廓
area1 = cv2.contourArea(contours[i])#轮廓面积1
area2 = cv2.contourArea(contours[j])#轮廓面积2
if area2 == 0:#无子轮廓
return False
ratio = area1 * 1.0 / area2
if abs(ratio - 25.0 / 9):# 5/3
return True
return False
判断后,我们获取三个轮廓的中心坐标
'''求轮廓中心坐标'''
def get_center(contours,i):
M=cv2.moments(contours[i]) #求矩阵
cx=int(M['m10']/M['m00']) #求x坐标
cy=int(M['m01']/M['m00']) #求y坐标
return cx,cy
'''判断中心间距'''
def detect_contours(vec):
distance_1=np.sqrt((vec[0]-vec[2])**2+(vec[1]-vec[3])**2)#1、2两点的距离
distance_2 = np.sqrt((vec[0] - vec[4]) ** 2 + (vec[1] - vec[5]) ** 2)#1、3两点的距离
distance_3 = np.sqrt((vec[2] - vec[4]) ** 2 + (vec[3] - vec[5]) ** 2)#2、3两点的距离
if sum((distance_1,distance_2,distance_3))/3<3:
return True
return False
其中原作者使用是否三角形作为了一个判断条件,是一个很好的思路。
def triangle(rec):#是否组成三角形
if len(rec) < 3:
return -1, -1, -1
'''判断边长是否满足三角形条件'''
for i in range(len(rec)):
for j in range(i + 1, len(rec)):
for k in range(j + 1, len(rec)):
distance_1 = np.sqrt((rec[i][0] - rec[j][0]) ** 2 + (rec[i][1] - rec[j][1]) ** 2)
distance_2 = np.sqrt((rec[i][0] - rec[k][0]) ** 2 + (rec[i][1] - rec[k][1]) ** 2)
distance_3 = np.sqrt((rec[j][0] - rec[k][0]) ** 2 + (rec[j][1] - rec[k][1]) ** 2)
if abs(distance_1 - distance_2) < 5:
if abs(np.sqrt(np.square(distance_1) + np.square(distance_2)) - distance_3) < 5:
return i, j, k
elif abs(distance_1 - distance_3) < 5:
if abs(np.sqrt(np.square(distance_1) + np.square(distance_3)) - distance_2) < 5:
return i, j, k
elif abs(distance_2 - distance_3) < 5:
if abs(np.sqrt(np.square(distance_2) + np.square(distance_3)) - distance_1) < 5:
return i, j, k
return -1, -1, -1
以上步骤结束,基本就可以对二维码进行一个粗略的定位了。那么接下去就是对二维码的裁剪处理了。
二、二维码的裁剪
为了使解码更为准确,我们需要将二维码从原图上裁剪下来,并进行尺寸的处理。
ss=np.concatenate((contours[rec[i][6]],contours[rec[j][6]],contours[rec[k][6]]))#矩阵拼接
rect=cv2.minAreaRect(ss)#最小外接矩形
box=cv2.boxPoints(rect)#矩形边缘
box=np.int0(box)
leftup = box[2][1]
rightup = box[0][1]
leftbuttom = box[1][0]
rightbuttom = box[3][0]
'''裁剪图片'''
new_image=image[leftup:rightup,leftbuttom:rightbuttom]
#new_image=image[43:1025,403:1387]
#cv2.imshow('img', new_image)
#cv2.waitKey(0)
new_image1=cv2.resize(new_image,(1024,1024))
#cv2.imshow('img', new_image1)
#cv2.waitKey(0)
return new_image1
我们通过简单测试,粗略地寻找除了几个点对图像进行裁剪,裁剪可以使得大部分的信息能够被读取,但对于太大的倾斜仍然无法有效地处理。