208 lines
7.0 KiB
Python
208 lines
7.0 KiB
Python
#!/usr/bin/env python
|
||
# -*- encoding: utf-8 -*-
|
||
'''
|
||
@File : roi_img_process.py
|
||
@Contact : zpyovo@hotmail.com
|
||
@License : (C)Copyright 2018-2019, Lab501-TransferLearning-SCUT
|
||
@Description :
|
||
|
||
@Modify Time @Author @Version @Desciption
|
||
------------ ------- -------- -----------
|
||
2024/1/7 22:57 Pengyu Zhang 1.0 None
|
||
'''
|
||
|
||
from __future__ import absolute_import
|
||
from __future__ import division
|
||
from __future__ import print_function
|
||
import cv2
|
||
import numpy as np
|
||
from matplotlib import pyplot as plt
|
||
|
||
def preprocess_image(image,size,blur):
|
||
# 将图像调整为固定大小
|
||
# image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
||
if size !=-1:
|
||
image = cv2.resize(image, (size, size), interpolation=cv2.INTER_AREA)
|
||
if size == -1:
|
||
image = cv2.cvtColor(np.array(image), cv2.COLOR_BGR2GRAY)
|
||
if blur:
|
||
kernel_size = 3
|
||
image = cv2.GaussianBlur(image, (kernel_size, kernel_size), sigmaX=1, sigmaY=0)
|
||
return image
|
||
def clos_open(input,B_p):
|
||
_, binary_image = cv2.threshold(input, B_p, 255, cv2.THRESH_BINARY)
|
||
# 定义结构元素(内核)
|
||
kernel = np.ones((3, 3), np.uint8)
|
||
|
||
# 开运算
|
||
opening = cv2.morphologyEx(binary_image, cv2.MORPH_OPEN, kernel)
|
||
|
||
# 定义结构元素(内核)
|
||
kernel = np.ones((3, 3), np.uint8)
|
||
# 闭运算
|
||
closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel)
|
||
|
||
return closing
|
||
|
||
|
||
def img_angle(input):
|
||
# canny边缘检测
|
||
eroded_canny = cv2.Canny(input, 50, 255, apertureSize=3)
|
||
contours, hierarchy = cv2.findContours(eroded_canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
||
|
||
# 寻找最大元素
|
||
k = 0
|
||
index = 0
|
||
if len(contours) != 0:
|
||
for i in range(len(contours)):
|
||
j = contours[i].size
|
||
if j > k:
|
||
k = j
|
||
index = i
|
||
|
||
# 拟合旋转矩形
|
||
cnt = contours[index]
|
||
rect = cv2.minAreaRect(cnt)
|
||
angle = rect[2]
|
||
box = cv2.boxPoints(rect)
|
||
|
||
box = np.int0(box)
|
||
|
||
# 对点按照y坐标排序(最上和最下的点)
|
||
box = box[box[:, 1].argsort()]
|
||
|
||
# 上边的两个点按照x坐标排序(决定左上和右上)
|
||
top_two = box[:2]
|
||
top_two = top_two[top_two[:, 0].argsort()]
|
||
|
||
# 下边的两个点按照x坐标排序(决定左下和右下)
|
||
bottom_two = box[2:]
|
||
bottom_two = bottom_two[bottom_two[:, 0].argsort()]
|
||
|
||
# 重新组合为左上、右上、右下、左下的顺序
|
||
ordered_box = np.array([top_two[0], top_two[1], bottom_two[1], bottom_two[0]])
|
||
|
||
return angle,ordered_box
|
||
|
||
def angel_affine(input,angle):
|
||
height, width = np.array(input).shape
|
||
center = (width // 2, height // 2)
|
||
if angle is not None and angle != 0.0:
|
||
if angle > 45.0:
|
||
angle = angle - 90
|
||
# rotate page if not straight relative to QR code
|
||
M = cv2.getRotationMatrix2D(center, angle, 1.0)
|
||
output = cv2.warpAffine(np.array(input), M, (width, height), flags=cv2.INTER_CUBIC,borderMode=cv2.BORDER_REPLICATE)
|
||
|
||
return output
|
||
|
||
|
||
def merge_overlapping_rectangles(rectangles):
|
||
if len(rectangles) <= 1:
|
||
return rectangles
|
||
|
||
merged_rectangles = []
|
||
for rect in sorted(rectangles, key=lambda x: x[2]*x[3], reverse=True):
|
||
x, y, w, h = rect
|
||
if not any((x < x2 + w2 and x + w > x2 and y < y2 + h2 and y + h > y2) for x2, y2, w2, h2 in merged_rectangles):
|
||
merged_rectangles.append(rect)
|
||
return merged_rectangles
|
||
|
||
|
||
def roi2_detector(input,min_area_threshold):
|
||
# 使用 Canny 边缘检测
|
||
edges = cv2.Canny(input, 50, 255, apertureSize=3)
|
||
|
||
# 寻找轮廓
|
||
contours, _ = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
|
||
# 临时存储矩形
|
||
temp_rectangles = []
|
||
|
||
# 识别矩形轮廓
|
||
for contour in contours:
|
||
# 轮廓近似
|
||
epsilon = 0.001 * cv2.arcLength(contour, True)
|
||
approx = cv2.approxPolyDP(contour, epsilon, True)
|
||
|
||
if len(approx) >= 4:
|
||
x, y, w, h = cv2.boundingRect(approx)
|
||
aspect_ratio = w / float(h)
|
||
area_contour = cv2.contourArea(contour)
|
||
if aspect_ratio >= 0.75 and aspect_ratio < 1.2 and min_area_threshold < area_contour < 15000:
|
||
area_bounding_rect = w * h
|
||
area_ratio = area_contour / area_bounding_rect
|
||
if 0.75 < area_ratio < 1.05:
|
||
temp_rectangles.append((x, y, w, h))
|
||
|
||
# 合并重叠的方框
|
||
merged_rectangles = merge_overlapping_rectangles(temp_rectangles)
|
||
|
||
# 选择并绘制最大的方框
|
||
if merged_rectangles:
|
||
outermost_rectangle = max(merged_rectangles, key=lambda x: x[2]*x[3])
|
||
rectangle_count = 1
|
||
return outermost_rectangle
|
||
else:
|
||
return None
|
||
from PIL import Image
|
||
|
||
def roi_img_processing(input):
|
||
input_ray = cv2.cvtColor(np.array(input), cv2.COLOR_BGR2GRAY)
|
||
img_resize = preprocess_image(input_ray, 128, blur=False)
|
||
img_closing = clos_open(img_resize,B_p=50) # 闭运算
|
||
min_area_threshold=6500
|
||
roi_coordinate = roi2_detector(img_closing,min_area_threshold)
|
||
if roi_coordinate is None:
|
||
img_closing = clos_open(img_resize, B_p=100) # 闭运算
|
||
roi_coordinate = roi2_detector(img_closing,min_area_threshold)
|
||
if roi_coordinate is None:
|
||
return None
|
||
x, y, w, h = roi_coordinate
|
||
# 截取图像
|
||
input_fix = img_resize[y+1:y-1 + h, x+1:x-1 + w]
|
||
output = preprocess_image(input_fix, 32, blur=True)
|
||
|
||
return output
|
||
|
||
def roi_detect(input):
|
||
size = 128
|
||
height, width, _ = input.shape
|
||
|
||
if height < size:
|
||
img_resize = cv2.resize(np.array(input), (size, size), interpolation=cv2.INTER_AREA)
|
||
else:
|
||
img_resize = cv2.resize(np.array(input), (size, size), interpolation=cv2.INTER_LINEAR)
|
||
image_gay = cv2.cvtColor(img_resize, cv2.COLOR_BGR2GRAY)
|
||
min_area_threshold = 1000
|
||
img_closing = clos_open(image_gay, B_p=50) # 闭运算
|
||
roi_coordinate = roi2_detector(img_closing,min_area_threshold)
|
||
|
||
if roi_coordinate is None :
|
||
img_closing = clos_open(img_resize, B_p=100) # 闭运算
|
||
roi_coordinate = roi2_detector(img_closing,min_area_threshold)
|
||
# print('150')
|
||
if roi_coordinate is None :
|
||
img_closing = clos_open(img_resize, B_p=150) # 闭运算
|
||
roi_coordinate = roi2_detector(img_closing,min_area_threshold)
|
||
# print('100')
|
||
if roi_coordinate is None :
|
||
img_closing = clos_open(img_resize, B_p=120) # 闭运算
|
||
roi_coordinate = roi2_detector(img_closing,min_area_threshold)
|
||
if roi_coordinate is None:
|
||
img_closing = clos_open(img_resize, B_p=75) # 闭运算
|
||
roi_coordinate = roi2_detector(img_closing,min_area_threshold)
|
||
if roi_coordinate is None:
|
||
return None
|
||
x, y, w, h = roi_coordinate
|
||
# 截取图像
|
||
input_fix = img_resize[y + 1:y - 1 + h, x + 1:x - 1 + w]
|
||
input_fix = Image.fromarray(np.uint8(input_fix))
|
||
return input_fix
|
||
def roi_minAreaRect(input):
|
||
img_closing = clos_open(input) # 闭运算
|
||
_, box = img_angle(img_closing) # 图像偏差角度
|
||
return box
|
||
|
||
|
||
|