我以你的代码为基础,得到了绿色矩形。我通过大小过滤框来消除包含大块图像的大框(甚至有一个框围绕整个图像)。从那里开始,我迭代地合并附近的框,直到没有重叠的框为止。我使用merge_margin变量来设置两个框需要多接近才能算作“重叠”。每个步骤中,我突出显示了最后合并的框和它找到的点。(这个gif被压缩得很厉害,所以你会看到一些伪影)
![enter image description here](https://istack.dev59.com/OZUyN.gif)
最终图像
![enter image description here](https://istack.dev59.com/e2YGd.webp)
import cv2
import numpy as np
def tup(point):
return (point[0], point[1]);
def overlap(source, target):
tl1, br1 = source;
tl2, br2 = target;
if (tl1[0] >= br2[0] or tl2[0] >= br1[0]):
return False;
if (tl1[1] >= br2[1] or tl2[1] >= br1[1]):
return False;
return True;
def getAllOverlaps(boxes, bounds, index):
overlaps = [];
for a in range(len(boxes)):
if a != index:
if overlap(bounds, boxes[a]):
overlaps.append(a);
return overlaps;
img = cv2.imread("test.png")
orig = np.copy(img);
blue, green, red = cv2.split(img)
def medianCanny(img, thresh1, thresh2):
median = np.median(img)
img = cv2.Canny(img, int(thresh1 * median), int(thresh2 * median))
return img
blue_edges = medianCanny(blue, 0, 1)
green_edges = medianCanny(green, 0, 1)
red_edges = medianCanny(red, 0, 1)
edges = blue_edges | green_edges | red_edges
_, contours,hierarchy = cv2.findContours(edges, cv2.RETR_EXTERNAL ,cv2.CHAIN_APPROX_SIMPLE)
boxes = [];
hierarchy = hierarchy[0]
for component in zip(contours, hierarchy):
currentContour = component[0]
currentHierarchy = component[1]
x,y,w,h = cv2.boundingRect(currentContour)
if currentHierarchy[3] < 0:
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),1)
boxes.append([[x,y], [x+w, y+h]]);
filtered = [];
max_area = 30000;
for box in boxes:
w = box[1][0] - box[0][0];
h = box[1][1] - box[0][1];
if w*h < max_area:
filtered.append(box);
boxes = filtered;
merge_margin = 20;
finished = False;
highlight = [[0,0], [1,1]];
points = [[[0,0]]];
while not finished:
finished = True;
print("Len Boxes: " + str(len(boxes)));
copy = np.copy(orig);
for box in boxes:
cv2.rectangle(copy, tup(box[0]), tup(box[1]), (0,200,0), 1);
cv2.rectangle(copy, tup(highlight[0]), tup(highlight[1]), (0,0,255), 2);
for point in points:
point = point[0];
cv2.circle(copy, tup(point), 4, (255,0,0), -1);
cv2.imshow("Copy", copy);
key = cv2.waitKey(1);
if key == ord('q'):
break;
index = 0;
while index < len(boxes):
curr = boxes[index];
tl = curr[0][:];
br = curr[1][:];
tl[0] -= merge_margin;
tl[1] -= merge_margin;
br[0] += merge_margin;
br[1] += merge_margin;
overlaps = getAllOverlaps(boxes, [tl, br], index);
if len(overlaps) > 0:
con = [];
overlaps.append(index);
for ind in overlaps:
tl, br = boxes[ind];
con.append([tl]);
con.append([br]);
con = np.array(con);
x,y,w,h = cv2.boundingRect(con);
w -= 1;
h -= 1;
merged = [[x,y], [x+w, y+h]];
highlight = merged[:];
points = con;
overlaps.sort(reverse = True);
for ind in overlaps:
del boxes[ind];
boxes.append(merged);
finished = False;
break;
index += 1;
cv2.destroyAllWindows();
copy = np.copy(orig);
for box in boxes:
cv2.rectangle(copy, tup(box[0]), tup(box[1]), (0,200,0), 1);
cv2.imshow("Final", copy);
cv2.waitKey(0);
编辑:这种低效率让我有点困扰。合并盒子的顺序并没有什么意义。你可以看到有很多步骤,小盒子合并成大盒子,而不是大盒子吃掉里面的一切并变大。结果发现这是一个非常容易修复的代码问题。由于新合并的盒子附加到盒子列表的末尾,我们可以反向索引,以使我们从大到小进行。
我将merge_margin更改为15,因为我认为这更接近问题中的目标解决方案。
![enter image description here](https://istack.dev59.com/6DkGb.gif)
import cv2
import numpy as np
def tup(point):
return (point[0], point[1]);
def overlap(source, target):
tl1, br1 = source;
tl2, br2 = target;
if (tl1[0] >= br2[0] or tl2[0] >= br1[0]):
return False;
if (tl1[1] >= br2[1] or tl2[1] >= br1[1]):
return False;
return True;
def getAllOverlaps(boxes, bounds, index):
overlaps = [];
for a in range(len(boxes)):
if a != index:
if overlap(bounds, boxes[a]):
overlaps.append(a);
return overlaps;
img = cv2.imread("test.png")
orig = np.copy(img);
blue, green, red = cv2.split(img)
def medianCanny(img, thresh1, thresh2):
median = np.median(img)
img = cv2.Canny(img, int(thresh1 * median), int(thresh2 * median))
return img
blue_edges = medianCanny(blue, 0, 1)
green_edges = medianCanny(green, 0, 1)
red_edges = medianCanny(red, 0, 1)
edges = blue_edges | green_edges | red_edges
_, contours,hierarchy = cv2.findContours(edges, cv2.RETR_EXTERNAL ,cv2.CHAIN_APPROX_SIMPLE)
boxes = [];
hierarchy = hierarchy[0]
for component in zip(contours, hierarchy):
currentContour = component[0]
currentHierarchy = component[1]
x,y,w,h = cv2.boundingRect(currentContour)
if currentHierarchy[3] < 0:
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),1)
boxes.append([[x,y], [x+w, y+h]]);
filtered = [];
max_area = 30000;
for box in boxes:
w = box[1][0] - box[0][0];
h = box[1][1] - box[0][1];
if w*h < max_area:
filtered.append(box);
boxes = filtered;
merge_margin = 15;
finished = False;
highlight = [[0,0], [1,1]];
points = [[[0,0]]];
while not finished:
finished = True;
print("Len Boxes: " + str(len(boxes)));
copy = np.copy(orig);
for box in boxes:
cv2.rectangle(copy, tup(box[0]), tup(box[1]), (0,200,0), 1);
cv2.rectangle(copy, tup(highlight[0]), tup(highlight[1]), (0,0,255), 2);
for point in points:
point = point[0];
cv2.circle(copy, tup(point), 4, (255,0,0), -1);
cv2.imshow("Copy", copy);
key = cv2.waitKey(1);
if key == ord('q'):
break;
index = len(boxes) - 1;
while index >= 0:
curr = boxes[index];
tl = curr[0][:];
br = curr[1][:];
tl[0] -= merge_margin;
tl[1] -= merge_margin;
br[0] += merge_margin;
br[1] += merge_margin;
overlaps = getAllOverlaps(boxes, [tl, br], index);
if len(overlaps) > 0:
con = [];
overlaps.append(index);
for ind in overlaps:
tl, br = boxes[ind];
con.append([tl]);
con.append([br]);
con = np.array(con);
x,y,w,h = cv2.boundingRect(con);
w -= 1;
h -= 1;
merged = [[x,y], [x+w, y+h]];
highlight = merged[:];
points = con;
overlaps.sort(reverse = True);
for ind in overlaps:
del boxes[ind];
boxes.append(merged);
finished = False;
break;
index -= 1;
cv2.destroyAllWindows();
copy = np.copy(orig);
for box in boxes:
cv2.rectangle(copy, tup(box[0]), tup(box[1]), (0,200,0), 1);
cv2.imshow("Final", copy);
cv2.waitKey(0);