目录
一、最小外接矩形
这里的图片是mask,类似于这样的:
绘制如上图片的最小外接矩阵:
def draw_min_rect_rectangle(mask_path):
image = cv2.imread(mask_path)
thresh = cv2.Canny(image, 128, 256)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
img = np.copy(image)
for cnt in contours:
x, y, w, h = cv2.boundingRect(cnt)
# 绘制矩形
cv2.rectangle(img, (x, y+h), (x+w, y), (0, 255, 255))
绘制结果:
也可以将矩形区域作成新的mask:
# 将最小内接矩形填充为白色
white = [255, 255, 255]
for col in range(x, x+w):
for row in range(y, y+h):
image[row, col] = white
那么我们的最小内接矩阵mask就绘制好了:
也可以通过x,y,w,h对图片进行切割:
pic = cv2.imread(original_img_path) # 读取mask对应的图片
cut = pic[y:y+h, x:x+w] # 根据内接矩形的顶点切割图片
cv2.imwrite(save_path, cut) # 保存切割好的图片
也可以通过最小内接矩形mask来进行切割:
rectangle_mask_gray = cv2.cvtColor(rectangle_mask, cv2.COLOR_RGB2GRAY) # 此处的image是我们之前获取的最小内接矩形的mask
pic = cv2.imread(original_img_path) # 读取mask对应的图像
out = cv2.bitwise_and(pic, pic, mask=rectangle_mask) # 根据mask切割
cv2.imshow("min rect rectangle mask cut img", out)
效果如下:
二、最大内接矩形
def maximum_internal_rectangle(mask_path):
img = cv2.imread(mask_path)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, img_bin = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(img_bin, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
contour = contours[0].reshape(len(contours[0]), 2)
rect = []
for i in range(len(contour)):
x1, y1 = contour[i]
for j in range(len(contour)):
x2, y2 = contour[j]
area = abs(y2 - y1) * abs(x2 - x1)
rect.append(((x1, y1), (x2, y2), area))
all_rect = sorted(rect, key=lambda x: x[2], reverse=True)
if all_rect:
best_rect_found = False
index_rect = 0
nb_rect = len(all_rect)
while not best_rect_found and index_rect < nb_rect:
rect = all_rect[index_rect]
(x1, y1) = rect[0]
(x2, y2) = rect[1]
valid_rect = True
x = min(x1, x2)
while x < max(x1, x2) + 1 and valid_rect:
if any(img[y1, x]) == 0 or any(img[y2, x]) == 0:
valid_rect = False
x += 1
y = min(y1, y2)
while y < max(y1, y2) + 1 and valid_rect:
if any(img[y, x1]) == 0 or any(img[y, x2]) == 0:
valid_rect = False
y += 1
if valid_rect:
best_rect_found = True
index_rect += 1
if best_rect_found:
# 如果要在灰度图img_gray上画矩形,请用黑色画(0,0,0)
cv2.rectangle(img, (x1, y1), (x2, y2), (255, 0, 0), 1)
cv2.imshow("rec", img)
cv2.waitKey(0)
else:
print("No rectangle fitting into the area")
else:
print("No rectangle found")
三、最大内接圆
先看效果:
再放代码:
# 读取图片,转灰度
mask = cv2.imread(mask_path)
mask_gray = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
# 识别轮廓
contours, _ = cv2.findContours(mask_gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 计算到轮廓的距离
raw_dist = np.empty(mask_gray.shape, dtype=np.float32)
for i in range(mask_gray.shape[0]):
for j in range(mask_gray.shape[1]):
raw_dist[i, j] = cv2.pointPolygonTest(contours[0], (j, i), True)
# 获取最大值即内接圆半径,中心点坐标
minVal, maxVal, _, maxDistPt = cv2.minMaxLoc(raw_dist)
minVal = abs(minVal)
maxVal = abs(maxVal)
# 画出最大内接圆
result = cv2.cvtColor(mask_gray, cv2.COLOR_GRAY2BGR)
radius = np.int(maxVal)
center_of_circle = maxDistPt
cv2.circle(result, maxDistPt, radius, (0, 255, 0), 2, 1, 0)
cv2.imshow('Maximum inscribed circle', result)
cv2.waitKey(0)
四、最小外接圆
效果:
代码:
def minimum_external_circle(mask_path):
img = cv2.imread(mask_path)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
contours, _ = cv2.findContours(img_gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[0]
(x, y), radius = cv2.minEnclosingCircle(cnt)
center = (int(x), int(y)) # 最小内接圆圆心
radius = int(radius)
cv2.circle(img, center, radius, (0, 255, 0), 2)
cv2.circle(img, center, 1, (0, 255, 0), 2)
cv2.imshow('ret', img)
cv2.waitKey(0)
五、拟合椭圆
效果:
代码:
def fit_ellipse(mask_path):
img = cv2.imread(mask_path)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
contours, _ = cv2.findContours(img_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 拟合椭圆
ellipse = cv2.fitEllipse(contours[0])
cv2.ellipse(img, ellipse, (255, 0, 255), 2)
ellipse_center = (int(ellipse[0][0]), int(ellipse[0][1])) # 椭圆圆心坐标
cv2.circle(img, ellipse_center, 1, (255, 0, 255), 2)
cv2.imshow('ellipse', img)
cv2.waitKey(0)