354 lines
12 KiB
Python
354 lines
12 KiB
Python
# -- coding: utf-8 --
|
||
import numpy as np
|
||
import cv2
|
||
import math
|
||
|
||
|
||
def _sobel(image):
|
||
'''
|
||
_sobel
|
||
'''
|
||
if image.ndim > 2:
|
||
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
||
# todo 增加几个参数 http://blog.csdn.net/sunny2038/article/details/9170013
|
||
_sobelx = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=1)
|
||
_sobely = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=1)
|
||
|
||
_sobelx = np.uint8(np.absolute(_sobelx))
|
||
_sobely = np.uint8(np.absolute(_sobely))
|
||
_sobelcombine = cv2.bitwise_or(_sobelx,_sobely)
|
||
return _sobelcombine
|
||
|
||
# ##################################################################
|
||
|
||
# # 展平
|
||
# img_flat = _im_gray.reshape((_im_gray.shape[0] * _im_gray.shape[1], 1))
|
||
|
||
|
||
# img_flat = np.float32(img_flat)
|
||
|
||
# # 迭代参数
|
||
# criteria = (cv2.TERM_CRITERIA_EPS + cv2.TermCriteria_MAX_ITER, 20, 0.0)
|
||
# flags = cv2.KMEANS_RANDOM_CENTERS
|
||
|
||
# # 进行聚类
|
||
# compactness, labels, centers = cv2.kmeans(img_flat, 20, None, criteria, 10, flags)
|
||
|
||
# segmented_img = labels.reshape(_im_gray.shape)
|
||
# _im_gray = np.uint8(segmented_img)
|
||
# _im_gray = cv2.equalizeHist(_im_gray)
|
||
|
||
# cv2.imshow("_im2", im)
|
||
# cv2.waitKey(0)
|
||
# ##################################################################
|
||
|
||
def _findContours(image):
|
||
'''
|
||
_findContours
|
||
http://blog.csdn.net/mokeding/article/details/20153325
|
||
'''
|
||
contours, _ = cv2.findContours(image.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
|
||
return sorted(contours, key=cv2.contourArea, reverse=True)
|
||
|
||
def _drawContours(image, contours, cidx=-1):
|
||
'''
|
||
_drawContours
|
||
'''
|
||
image_contour = cv2.drawContours(image, contours, -1, (255, 255, 255), 1)
|
||
return image_contour
|
||
|
||
import time
|
||
class CropLayer(object):
|
||
def __init__(self, params, blobs):
|
||
self.xstart = 0
|
||
self.xend = 0
|
||
self.ystart = 0
|
||
self.yend = 0
|
||
# Our layer receives two inputs. We need to crop the first input blob
|
||
# to match a shape of the second one (keeping batch size and number of channels)
|
||
def getMemoryShapes(self, inputs):
|
||
inputShape, targetShape = inputs[0], inputs[1]
|
||
batchSize, numChannels = inputShape[0], inputShape[1]
|
||
height, width = targetShape[2], targetShape[3]
|
||
|
||
self.ystart = int((inputShape[2] - targetShape[2]) / 2)
|
||
self.xstart = int((inputShape[3] - targetShape[3]) / 2)
|
||
self.yend = self.ystart + height
|
||
self.xend = self.xstart + width
|
||
|
||
return [[batchSize, numChannels, height, width]]
|
||
|
||
def forward(self, inputs):
|
||
return [inputs[0][:,:,self.ystart:self.yend,self.xstart:self.xend]]
|
||
|
||
class Arguments:
|
||
def __init__(self):
|
||
self.description = ""
|
||
self.input = "./images/x.png"
|
||
self.prototxt = "./deploy.prototxt"
|
||
self.caffemodel = "./hed_pretrained_bsds.caffemodel"
|
||
self.width = 360
|
||
self.height = 115
|
||
self.savefile = "./1.jpg"
|
||
|
||
def dnn(im):
|
||
args = Arguments()
|
||
args.width = im.shape[1]
|
||
args.height = im.shape[0]
|
||
args.input = im
|
||
# Load the model.
|
||
net = cv2.dnn.readNetFromCaffe(args.prototxt, args.caffemodel)
|
||
# 设置网络运行参数
|
||
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
|
||
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU) # 或者GPU
|
||
# net.setPreferableTarget(cv2.dnn.DNN_TARGET_OPENCL)
|
||
cv2.dnn_registerLayer('Crop', CropLayer)
|
||
kWinName = 'Holistically-Nested_Edge_Detection'
|
||
mean_value = cv2.mean(im)
|
||
inp = cv2.dnn.blobFromImage(im, scalefactor=1.5, size=(args.width, args.height),
|
||
mean=mean_value,
|
||
swapRB=True, crop=True)
|
||
net.setInput(inp)
|
||
# edges = cv2.Canny(frame,args.width,args.height)
|
||
# edges = cv2.Canny(frame,frame.shape[1],frame.shape[0])
|
||
out = net.forward()
|
||
out = out[0, 0]
|
||
_im_gray = cv2.resize(out, (im.shape[1], im.shape[0]))
|
||
_im_gray = 255 * _im_gray
|
||
# print(out)
|
||
_im_gray = _im_gray.astype(np.uint8)
|
||
_im_gray = cv2.resize(_im_gray, (640, 480))
|
||
cv2.imshow('Input', _im_gray)
|
||
cv2.waitKey(0)
|
||
|
||
def Scharr(image):
|
||
'''
|
||
_sobel
|
||
'''
|
||
if image.ndim > 2:
|
||
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
||
# todo 增加几个参数 http://blog.csdn.net/sunny2038/article/details/9170013
|
||
_scharrx = cv2.Scharr(image, cv2.CV_8U, dx=1, dy=0, scale=1, delta=0, borderType=cv2.BORDER_DEFAULT)
|
||
_scharry = cv2.Scharr(image, cv2.CV_8U, dx=0, dy=1, scale=1, delta=0, borderType=cv2.BORDER_DEFAULT)
|
||
|
||
_scharrx = np.uint8(np.absolute(_scharrx))
|
||
_scharry = np.uint8(np.absolute(_scharry))
|
||
_sobelcombine = cv2.bitwise_or(_scharrx,_scharry)
|
||
|
||
return _sobelcombine
|
||
|
||
def cal_conners_edges_sort(im, thresh_hold = 80, minLineLength = 400):
|
||
|
||
_im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
|
||
# for test
|
||
_im_gray = cv2.GaussianBlur(_im_gray, (5, 5), 0)
|
||
_im_edge_sobel = _sobel(_im_gray)
|
||
# _im_edge_sobel = Scharr(_im_gray)
|
||
|
||
_, _im_thresh = cv2.threshold(_im_edge_sobel, 5, 255, cv2.THRESH_BINARY)
|
||
|
||
cnts = _findContours(_im_thresh)
|
||
for contour in cnts:
|
||
if cv2.contourArea(contour) > 500:
|
||
# 计算轮廓的边界框
|
||
x, y, w, h = cv2.boundingRect(contour)
|
||
# 在原图上绘制矩形
|
||
cv2.rectangle(_im, (x, y), (x + w, y + h), (0, 255, 0), 2)
|
||
cv2.imshow("_im2", _im_thresh)
|
||
cv2.waitKey(0)
|
||
|
||
_lines = cv2.HoughLinesP(_im_thresh, 1, np.pi / 180, thresh_hold, minLineLength=minLineLength, maxLineGap=120)
|
||
|
||
# for test
|
||
for _line in _lines:
|
||
x1,y1,x2,y2 = _line[0]
|
||
cv2.line(_im, (x1,y1), (x2,y2), (0,255,0), 1)
|
||
# for test
|
||
cv2.imshow("_im", _im)
|
||
cv2.imshow("_im2", _im_edge_sobel)
|
||
cv2.waitKey(0)
|
||
|
||
# print(len(_lines))
|
||
_line4 = []
|
||
for _line in _lines:
|
||
x1,y1,x2,y2 = _line[0]
|
||
if x2 == x1: x2 += 0.001
|
||
theta = np.arctan((y2 - y1) / (x2 - x1)) * (180 / math.pi)
|
||
x2 = int(x2)
|
||
r = math.sqrt(pow((y2 - y1), 2) + pow((x2 - x1), 2))
|
||
# 计算直线的斜率(如果 1 ≠ 2)
|
||
if x2 == x1: x2 += 0.001 # 如果x2 == x1,会出现分母为0
|
||
m = (y2 - y1) / (x2 - x1)
|
||
x2 = int(x2)
|
||
A, B, C = m, -1, y1 - m * x1
|
||
brepeat = False
|
||
for i in range(len(_line4)):
|
||
if abs(abs(theta) - abs(_line4[i][4])) < 30: # 20°
|
||
cx, cy = (_line4[i][2] + _line4[i][0]) / 2, (_line4[i][3] + _line4[i][1]) / 2
|
||
d = abs(A * cx + B * cy + C) / math.sqrt(pow(A, 2) + pow(B, 2))
|
||
r_max = max(_line4[i][5], r)
|
||
if d < r_max / 3:
|
||
brepeat = True
|
||
if (r > _line4[i][5]) :
|
||
_line4[i] = [x1,y1,x2,y2, theta, r]
|
||
if not brepeat :
|
||
_line4.append([x1,y1,x2,y2, theta, r])
|
||
# print(x1,y1,x2,y2, theta, r)
|
||
|
||
# # for test
|
||
for x1,y1,x2,y2, theta, r in _line4:
|
||
cv2.line(_im, (x1,y1), (x2,y2), (0,255,0), 10)
|
||
print(x1,y1,x2,y2, theta, r)
|
||
_im_samll = cv2.resize(_im, (500, 500))
|
||
# for test
|
||
cv2.imshow("_im", _im_samll)
|
||
cv2.waitKey(0)
|
||
|
||
# 4条边排序
|
||
# assert(len(_line4) == 4)
|
||
_line4_sort = []
|
||
Ax, Bx, Cx = 1, 0, 0
|
||
Ay, By, Cy = 0, 1, 0
|
||
min_dx, max_dx, min_dy, max_dy = 10000, 0, 10000, 0
|
||
min_dx_idx, max_dx_id, min_dy_id, max_dy_id = -1, -1, -1, -1
|
||
for i in range(len(_line4)):
|
||
cx, cy = (_line4[i][2] + _line4[i][0]) / 2, (_line4[i][3] + _line4[i][1]) / 2
|
||
dx = abs(Ay * cx + By * cy + Cy) / math.sqrt(pow(Ay, 2) + pow(By, 2))
|
||
dy = abs(Ax * cx + Bx * cy + Cx) / math.sqrt(pow(Ax, 2) + pow(Bx, 2))
|
||
if dx < min_dx:
|
||
min_dx = dx
|
||
min_dx_idx = i
|
||
if dx > max_dx:
|
||
max_dx = dx
|
||
max_dx_id = i
|
||
if dy < min_dy:
|
||
min_dy = dy
|
||
min_dy_id = i
|
||
if dy > max_dy:
|
||
max_dy = dy
|
||
max_dy_id = i
|
||
_line4_sort = _line4[min_dx_idx], _line4[max_dy_id], _line4[max_dx_id], _line4[min_dy_id]
|
||
print(_line4_sort)
|
||
|
||
# # for test
|
||
for x1,y1,x2,y2, theta, r in _line4_sort:
|
||
cv2.line(_im, (x1,y1), (x2,y2), (0,0,255), 10)
|
||
print(x1,y1,x2,y2, theta, r)
|
||
_im_samll = cv2.resize(_im, (500, 500))
|
||
# for test
|
||
cv2.imshow("_im", _im_samll)
|
||
cv2.waitKey(0)
|
||
|
||
# 找四个交点
|
||
_conners4_sort = [0,0,0,0]
|
||
for i in range(len(_line4_sort)):
|
||
x1, y1, x2, y2, _, _ = _line4_sort[i]
|
||
x1_next, y1_next, x2_next, y2_next, _, _ = _line4_sort[(i + 1) % 4]
|
||
|
||
# 检查是否为垂直线
|
||
# if x2 - x1 == 0:
|
||
# A, B, C = 1, 0, -x1 # 垂直线
|
||
# else:
|
||
if x2 == x1: x2 += 0.00001 # 如果x2 == x1,会出现分母为0
|
||
m = (y2 - y1) / (x2 - x1)
|
||
x2 = int(x2)
|
||
A, B, C = m, -1, y1 - m * x1
|
||
|
||
# if x2_next - x1_next == 0:
|
||
# A_next, B_next, C_next = 1, 0, -x1_next # 垂直线
|
||
# else:
|
||
if x2_next == x1_next: x2_next += 0.001 # 如果x2 == x1,会出现分母为0
|
||
m_next = (y2_next - y1_next) / (x2_next - x1_next)
|
||
x2_next = int(x2_next)
|
||
A_next, B_next, C_next = m_next, -1, y1_next - m_next * x1_next
|
||
|
||
# 检查是否平行
|
||
if A * B_next == A_next * B:
|
||
continue # 跳过平行的线段
|
||
|
||
# 计算交点
|
||
x_p = (B_next * C - B * C_next) / (A_next * B - A * B_next)
|
||
y_p = (A * x_p + C) / - B
|
||
|
||
# 确保交点在图像范围内
|
||
if 0 <= int(x_p) < _im.shape[1] and 0 <= int(y_p) < _im.shape[0]:
|
||
_conners4_sort[(i + 1) % 4] = [int(x_p), int(y_p)]
|
||
|
||
assert(len(_conners4_sort) == 4)
|
||
|
||
return _conners4_sort, _line4_sort
|
||
|
||
|
||
def cal_sub_conners(im, conners4_sort, line4_sort, sub_pixels=100):
|
||
assert(len(conners4_sort)==4)
|
||
|
||
for i in range(4):
|
||
cx, cy = conners4_sort[i]
|
||
x = int(cx - sub_pixels / 2)
|
||
if x < 0: x = 0
|
||
y = int(cy - sub_pixels / 2)
|
||
if y < 0: y = 0
|
||
w = sub_pixels
|
||
h = sub_pixels
|
||
|
||
roi = im[y:y+h, x:x+w].copy()
|
||
roi_gray = cv2.cvtColor(roi, cv2.COLOR_RGB2GRAY)
|
||
roi_gray = cv2.Canny(roi_gray, threshold1=100, threshold2=200)
|
||
_tmp_corners = cv2.goodFeaturesToTrack(roi_gray, maxCorners=100, qualityLevel=0.001, minDistance=2)
|
||
|
||
roi_cx = cx - x
|
||
roi_cy = cy - y
|
||
min = 10000
|
||
tar_conner = []
|
||
|
||
for conner in _tmp_corners:
|
||
conner = conner.tolist()[0]
|
||
d = math.sqrt(pow((conner[0] - roi_cx), 2) + pow((conner[1] - roi_cy), 2))
|
||
if d < min :
|
||
min = d
|
||
tar_conner = [conner[0], conner[1]]
|
||
cv2.circle(_im, (int(conner[0]+x), int(conner[1]+y)), 1, (255,0,0), -1)
|
||
cv2.circle(roi, (int(roi_cx), int(roi_cy)), 2, (0,0,255), -1)
|
||
cv2.circle(roi, (int(tar_conner[0]), int(tar_conner[1])), 2, (255,0,0), -1)
|
||
cv2.circle(_im, (int(roi_cx+x), int(roi_cy+y)), 2, (0,0,255), -1)
|
||
cv2.circle(_im, (int(tar_conner[0]+x), int(tar_conner[1]+y)), 2, (255,0,0), -1)
|
||
# corners = np.int0(corners)
|
||
|
||
# for test
|
||
cv2.imshow("roi", roi)
|
||
cv2.waitKey(0)
|
||
|
||
if __name__ == '__main__':
|
||
|
||
_im = cv2.imread("./3_roi_image.png")
|
||
|
||
edge = np.sqrt(pow((0.323 - 0.32222), 2)
|
||
+ pow((1.32- 14.2), 2)
|
||
+ pow((41 - 32.1), 2))
|
||
cv2.putText(_im, str(edge)[:6], (int((23+23)/2), int((23+32)/2)), \
|
||
cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
|
||
|
||
|
||
_gray = cv2.cvtColor(_im, cv2.COLOR_BGR2GRAY)
|
||
# 测试自适应阈值分割
|
||
# thresh = cv2.adaptiveThreshold(_gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
|
||
# t, result_img = cv2.threshold(_gray, 5, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
|
||
# print(t)
|
||
# cv2.imshow("thresh", result_img)
|
||
# cv2.waitKey(0)
|
||
|
||
|
||
_conners4_sort, _line4_sort = cal_conners_edges_sort(_im)
|
||
|
||
# cal_sub_conners(_im, _conners4_sort, _line4_sort)
|
||
|
||
for i in range(4):
|
||
x1, y1, x2, y2, _, _ = _line4_sort[i]
|
||
x_p, y_p = _conners4_sort[i]
|
||
# # for test
|
||
cv2.circle(_im, (int(x_p), int(y_p)), 2, (0,0,255), -1)
|
||
cv2.line(_im, (x1,y1), (x2,y2), (0,255,0), 1)
|
||
|
||
cv2.imwrite("./2_roi_imagerest.png", _im)
|
||
cv2.imshow("im_edge", _im)
|
||
cv2.waitKey(0) |