(Reference:link.)
1.笛卡尔坐标系中一条直线,对应霍夫空间的一个点。
霍夫空间中的 k k k 和 q q q 就相当于笛卡尔坐标系中的 x x x 和 y y y
2.霍夫空间的一条直线,对应笛卡尔坐标系的一个点
3 .两个点对应霍夫空间的情形
4.三点共线对应霍夫空间的情形
5.多个点,可构成不止一条直线的情况
但是如果像下图这种情况呢?也即直线斜率为无穷大的情况
k = ∞ k=∞ k=∞是不方便表示的,而且 q q q 也不便于表示,Question:如何解决?
Answer:笛卡尔坐标系中,借用极坐标进行表示
在极坐标系下,极坐标的点→霍夫空间的直线
只不过霍夫空间不再是 [ k , q ] [k,q] [k,q]的参数,而是 [ ρ , θ ] [\rho,\theta] [ρ,θ]的参数,
给出对比图:
Reference: link.
上述的 θ \theta θ = − 90 -90 −90~ 180 180 180 应改为 [ − 90 , 90 ] [-90,90] [−90,90]或者 [ 0 , 180 ] [0,180] [0,180]
import cv2
import numpy as np
img = cv2.imread('book.jpg')
img1 = img.copy()
img2 = img.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img = cv2.GaussianBlur(gray, (3, 3), 0)
edges = cv2.Canny(gray, 50, 150) #first,use canny to detect edges
#======================method one : Hough transform==================
lines = cv2.HoughLines(edges, 1, np.pi/180, 100)
#the last param means :Only lines that get >=x votes will be returned
for line in lines:
rho = line[0][0]
theta = line[0][1]
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(img1, (x1, y1), (x2, y2), (0 ,206 ,209), 2)
#========method two : the probabilistic Hough transform============
lines = cv2.HoughLinesP(edges, 1, np.pi/180,threshold=50, minLineLength=53,maxLineGap=10)
for line in lines:
x1 = line[0][0] #end-point one
y1 = line[0][1]
x2 = line[0][2] #end-point two
y2 = line[0][3]
cv2.line(img2, (x1, y1), (x2, y2), (132, 112 ,255), 2)
cv2.imshow('Hough transfrom', img1)
cv2.imshow('the probabilistic Hough transform', img2)
cv2.waitKey(0)
代码如下(示例):
import numpy as np
import cv2
def MyFastHoughLine(edges,rho_step=1, angle_step=1, threshold=5,linesMax=20):
"""Hough transform for lines
utilize numpy's matrix multiply to make computation more efficient in both momory and time
when in stage1 filling accumulator
input:
: edges - 2D binary image with nonzeros representing edges
: angle_step - Default step is 1.
: lines_are_white - boolean indicating whether lines to be detected are white
: threshold - one line must have more than this value in accumulator vote
return:
: accumulator - 2D array of the hough transform accumulator
: resultLines - lists composed of many [line_i's rho , line_i'theta]
"""
width, height = edges.shape
# Rho and Theta ranges
thetas = np.deg2rad(np.arange(-90.0, 90.0, angle_step)) #theta sequence
numtheta = len(thetas)
maxdist = int(np.ceil(np.sqrt(width*width + height*height)))
rhos = np.arange(-maxdist, maxdist, rho_step) #rho sequence
numrho = len(rhos)
# Cache some reusable values
cos_theta = np.cos(thetas)
sin_theta = np.sin(thetas)
#===============stage 1. fill accumulator================================
accumulator = np.zeros((numrho+2, numtheta+2))
#why+2? To simplify the "margin case" process in stage2's NMS
y_idxs, x_idxs = np.nonzero(edges) #(row, col) indexes to edges
# z.reshape(-1,1): reshape z into an array with only 1 coloumn
# matrix(aXb) = matrix0(aX1) X matrix1(1Xb)
xcosthetas = np.dot(x_idxs.reshape((-1,1)), cos_theta.reshape((1,-1)))
ysinthetas = np.dot(y_idxs.reshape((-1,1)), sin_theta.reshape((1,-1)))
rhosmat = np.round(xcosthetas + ysinthetas) + maxdist # ρ= x*cosθ +y*sinθ
rhosmat = rhosmat.astype(np.int16) #rhosmat's shape = num_edgeDots * numtheta
for i in range(numtheta): #accumulator's shape = (2+numrho) * (2+numtheta)
rhosValue,counts = np.unique(rhosmat[:,i], return_counts=True)
for j in range(len(counts)):
rhoidx = rhosValue[j]+1
accumulator[rhoidx,i+1] = counts[j]
# accumulator[rhos+1 ,i+1] = counts
#===============stage 2. NMS-find local maximums==============================
lines = [] # a list composed of many [[rho_idx,theta_idx],count_i]
for i in range(0,numrho):
for j in range(0,numtheta):
count = accumulator[i+1,j+1]
if( count > threshold
and count > accumulator[i ,j+1] # without =?
and count >= accumulator[i+2,j+1] # but with =?
and count > accumulator[i+1,j ]
and count >= accumulator[i+1,j+2]):
theta = thetas[j]
rho = rhos[i]
lines.append([[rho,theta],count])
#===============stage 3. sort detected lines by vote value=====================
lines.sort(key = lambda x:x[1],reverse=True)
#===============stage 4. store the first min(total,linesMax) lines=============
linesMax = min(linesMax, len(lines))
resultLines = []
for i in range(linesMax):
tmp = lines[i][0]
resultLines.append(tmp)
return accumulator, resultLines
img = cv2.imread('book.jpg')
img1 = img.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (3, 3), 0)
edges = cv2.Canny(blur, 50, 150)
edges = cv2.dilate(edges,(3,3))
edges = cv2.erode(edges,(3,3)) #to get more fluent lines
#===================HoughLines=======================
accumulator, lines = MyFastHoughLine(edges)
for line in lines:
rho = line[0]
theta = line[1]
# print(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(img1, (x1, y1), (x2, y2), (0 ,206 ,209), 2)
cv2.imwrite("MyHoughLines.png",img1)
cv2.imshow('Hough transfrom', img1)
cv2.waitKey(0)