霍夫(Hough)变换
题目:计算黑子之间的距离与白字之间的距离,得到两个最大值,运用直线画出连接两段距离最大的黑子和白子的直线,运用hough直线检验出棋盘的中本来的黑线,以不同颜色画出。
from cv2 import cv2
from matplotlib import pyplot as plt
import numpy as np
import math
def calDistance(img):
cimg = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cv2.imshow("cimg", cimg)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 进行霍夫圆检测,参数为:单通道图像(灰度图),检测方法,累加器分辨率与图像分辨率的反比,两圆的最小距离,
# param1:用于处理边缘检测的梯度值方法, param2:累加器阈值, 最小半径,最大半径
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 20, param1=100, param2=27, minRadius=10, maxRadius=50)
MAX = 0
for num in range(0, 10): # white is 9, black is 10,最多循环10次就可以遍历所有圆
count = num
#print("num:{}".format(num))
for i in circles[0, num:]: # 获取圆心的坐标,从第num个开始,即每个圆都会和其他圆连接一次,测量距离
#print("count:{}".format(count))
if count is num: # 当前是循环的开头时
# lastPoint = (i[0], i[1])
# 记录当前圆心作为标记点
lastX = i[0]
lastY = i[1]
# print("last:")
# print((lastX,lastY))
else: # 循环的第二位开始,计算两圆心距离
# newPoint = (i[0], i[1])
# 当前圆心与标记点测距
newX = i[0]
newY = i[1]
# print("new")
# print((newX,newY))
# 将计算分步,适度调节
minus1 = lastX - newX # 得到差值
minus2 = lastY - newY # 不能反写,会溢出
# print(minus1)
# print(minus2)
part1 = math.pow(minus1, 2) # 求平方
part2 = math.pow(minus2, 2)
dis = int(math.sqrt(part1 + part2)) # 开根号求两圆心距离
# print(dis)
# 如果当前两圆心距离dis大于最大距离,则替换最大距离MAX
if dis > MAX:
MAX = dis
# 记录距离最大时的两点坐标,用于连线
point1 = (newX,newY)
point2 = (lastX,lastY)
# 根据圆心坐标画圈,显示检测到的棋子
cv2.circle(cimg, (i[0], i[1]), 2, (0, 0, 255), 3)
cv2.circle(cimg, (i[0], i[1]), i[2], (0, 255, 0), 2)
count += 1
print("MAX:{}".format(MAX))
# 将最大距离的两个圆心连起来
cv2.line(cimg,point1,point2,(0,0,255),3)
cv2.imshow('cimg',cimg)
cv2.waitKey(0)
cv2.destroyAllWindows()
readimg = cv2.imread('../image/weiqi.png', 0) # 读取灰度图,用于下面的霍夫检测
blurimg = cv2.medianBlur(readimg, 5)
img = cv2.cvtColor(blurimg,cv2.COLOR_GRAY2BGR) # 将灰度图转化为BGR原图,用于显示霍夫变换绘画直线的图像
img1 = cv2.threshold(blurimg,127,255,cv2.THRESH_TOZERO)[1] # white - 9,二值化将黑棋子去除,只检测白棋子
img2 = cv2.threshold(blurimg,153,255,cv2.THRESH_TOZERO_INV)[1] # black - 10,二值化将白棋子去除,只检测黑棋子
# 使用函数,计算最大圆心距离,并绘制出图像
calDistance(img1)
calDistance(img2)
edges = cv2.Canny(readimg,50,150,apertureSize=3) # 通过边缘检测,使得图像更加分明,便于霍夫变换时绘画直线
cv2.imshow('edge',edges)
cv2.waitKey(0)
# 霍夫变换,cv2.HoughLines
lines = cv2.HoughLines(edges,1,np.pi/180,114)
# for rho,theta in lines[0]: # 此语句只能显示一条直线
# 将霍夫变换检测到的直线全部绘画出来
for i in range(0,len(lines)):
rho,theta = lines[i][0][0],lines[i][0][1] # 获取直线的rho和theta角度
# 线段的两端坐标求解,从极坐标转换
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
cv2.line(img,(x1,y1),(x2,y2),(0,255,0),2)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
实现效果:
原图:
求白棋子间的最大距离:
求黑棋子间的最大距离:
用直线绘出棋盘格子:
结语: 本题采用霍夫圆检测得到各个圆的信息,但是也可以通过模板匹配,得到每个圆的外接矩形的左上角坐标,进而得到各个圆的信息。