我之前利用四个角点的位置特征找到了角点,详见:透视变换法校正轮廓(全过程) | python代码
利用Harris角点检测输出长方形的四个角点
1. 原理
1.1 公式
角点响应函数:
因此:设定一个阈值,分数大于这个阈值的像素就对应角点。
1.2 参数设置
dst = cv2.cornerHarris(src, blockSize, ksize, k[, dst[, borderType]])
blockSize—计算在时候的矩阵大小
Ksize—窗口大小
k—表示计算角度响应时候的参数大小,默认在0.04-0.06之间
阈值t—用来过滤角度响应
2. 初步实现
2.1 效果展示
原图:
效果图:
2.2 代码展示
import cv2
from matplotlib import pyplot as plt
import numpy as np
img = cv2.imread('D:/python_opencv/H_1.jpg')
cv2.namedWindow("img",cv2.cv2.WINDOW_FREERATIO)
cv2.imshow("img",img)
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
h,w = img.shape[0],img.shape[1]
#Harris角点检测
gray_img = np.float32(gray_img)
corners_img = cv2.cornerHarris(gray_img,blockSize=2, ksize=3, k=0.04)
cv2.imshow("corners_img",corners_img)
#膨胀
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
dst = cv2.dilate(corners_img, kernel)
cv2.imshow("dst",dst)
#阈值设定
img[dst > 0.005*dst.max()] = [225, 0, 0]
cv2.namedWindow("Harris",cv2.cv2.WINDOW_FREERATIO)
cv2.imshow('Harris', img)
count = 0
print(h,w)
#左上角
for i in range(h//2):
for j in range(w//2):
if img[i][j][0] == 225:
cv2.circle(img,(j,i),5,(0,255,255),0)
count += 1
#右上角
for i in range(h//2):
for j in range(w//2,w):
if img[i][j][0] == 225:
cv2.circle(img,(j,i),5,(0,255,255),0)
count += 1
#左下角
for i in range(h//2,h):
for j in range(w//2):
if img[i][j][0] == 225:
cv2.circle(img,(j,i),5,(0,255,255),0)
count += 1
#右下角
for i in range(h//2,h):
for j in range(w//2,w):
if img[i][j][0] == 225:
cv2.circle(img,(j,i),5,(0,255,255),0)
count += 1
print(count)
cv2.namedWindow("final",cv2.cv2.WINDOW_FREERATIO)
cv2.imshow('final', img)
cv2.waitKey(0)
3. 改进方案
要求:只保留4个角点
3.1 效果展示
原图:
效果图:
3.2 原理解释
每部分角点的存储方式是顺时针,见下图。所以左上和右上图在第一次循环时就得出来,左下图就需要循环到最后出来,右下图还需要精细化处理,暂不讨论。
3.3 代码展示
import cv2
from matplotlib import pyplot as plt
import numpy as np
img = cv2.imread('D:/python_opencv/H_1.jpg')
src = img.copy()
cv2.namedWindow("img",cv2.cv2.WINDOW_FREERATIO)
cv2.imshow("img",img)
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray_img, (7, 7), 0)
h,w = img.shape[0],img.shape[1]
#Harris角点检测
gray_img = np.float32(gray)
corners_img = cv2.cornerHarris(gray_img,blockSize=2, ksize=3, k=0.04)
cv2.imshow("corners_img",corners_img)
#膨胀
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(3, 3))
dst = cv2.dilate(corners_img, kernel)
cv2.imshow("dst",dst)
#阈值设定
img[dst > 0.005*dst.max()] = [225, 0, 0]
cv2.namedWindow("Harris",cv2.cv2.WINDOW_FREERATIO)
cv2.imshow('Harris', img)
count = 0
print(h,w)
upLeftX = 0
upLeftY = 0
downLeftX = 0
downLeftY = 0
upRightX = 0
upRightY = 0
downRightX = 0
downRightY = 0
#左上角
for i in range(h//2):
for j in range(w//2):
if img[i][j][0] == 225:
cv2.circle(img,(j,i),5,(0,255,255),-1)
count += 1
if upLeftX == 0 and upLeftY == 0 :
upLeftX = i
upLeftY = j
break
if upLeftX or upLeftY:
break
#右上角
for i in range(h//2):
for j in range(w//2,w):
if img[i][j][0] == 225:
cv2.circle(img,(j,i),5,(0,255,255),-1)
count += 1
if upRightX == 0 and upRightY == 0:
upRightX = i
upRightY = j
break
if upRightX or upRightY:
break
#左下角
for i in range(h//2,h):
for j in range(w//2):
if img[i][j][0] == 225:
cv2.circle(img,(j,i),5,(0,255,255),-1)
count += 1
downLeftX = i
downLeftY = j
#右下角
for i in range(h//2,h):
for j in range(w//2,w):
if img[i][j][0] == 225:
cv2.circle(img,(j,i),5,(0,255,255),-1)
count += 1
downRightX = i
downRightY = j
cv2.line(img, (0,h//2), (w,h//2), (0,0,255))
cv2.line(img, (w//2,0), (w//2,h), (0,0,255))
cv2.namedWindow("all_Harris",cv2.cv2.WINDOW_FREERATIO)
cv2.imshow('all_Harris', img)
cv2.circle(src,(upLeftY,upLeftX),5,(0,255,255),-1)
cv2.circle(src,(upRightY,upRightX),5,(0,255,255),-1)
cv2.circle(src,(downLeftY,downLeftX),5,(0,255,255),-1)
cv2.circle(src,(downRightY,downRightX),5,(0,255,255),-1)
print(count)
cv2.namedWindow("final",cv2.cv2.WINDOW_FREERATIO)
cv2.imshow('final', src)
cv2.waitKey(0)