1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
|
from os.path import isfile, join from os import listdir import os import shutil import subprocess from collections import Counter import math import cv2 as cv import numpy as np import logging def find_color_max_rect(img, lower, upper): ''' 查找lower-upper指定的颜色区域最大的轮廓, lower, upper为hsv颜色空间''' hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV) binary = cv.inRange(hsv, lower, upper) kernel = np.ones((20, 20), np.uint8) closing = cv.morphologyEx(binary, cv.MORPH_CLOSE, kernel) contours, _ = cv.findContours( closing, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) logging.info("find start contours:%d" % len(contours)) max_area = 0 for c in contours: c_area = cv.contourArea(c) if c_area > max_area: max_area = c_area max_c = c return cv.boundingRect(max_c) def find_start(img): ''' 查找开始位置--迷宫开始图片的矩形''' lower_red = np.array([0, 0, 100]) upper_red = np.array([15, 255, 200]) return find_color_max_rect(img, lower_red, upper_red) def find_end(img): ''' 查找结束位置--迷宫目标图片的矩形''' lower_yellow = np.array([20, 0, 100]) upper_yellow = np.array([30, 250, 250]) return find_color_max_rect(img, lower_yellow, upper_yellow) def show_rects(img, rects): "显示矩形区域" ret = img.copy() for [x, y, w, h] in rects: cv.rectangle(ret, (x, y), (x+w, y+h), (0, 0, 255), 2) cv.imshow('rects', ret) cv.imwrite('show.jpg', ret) cv.waitKey(0) def uniq_lines(lines, precision=5): '''按照precision指定的误差统一直线''' sort_lines = lines.copy() sort_lines.sort() uniq_sort_lines = list(set(sort_lines)) uniq_sort_lines.sort() prev = uniq_sort_lines[0] result = [prev] for p in uniq_sort_lines[1:]: diff = abs(p - prev) if diff > precision: result.append(p) else: mp = min(p, prev) result[-1] = (mp + int(diff/2)) prev = p return result def find_lines(img, min_length=50): "查找线条,返回[horz_lines, vert_lines]" src = cv.cvtColor(img, cv.COLOR_BGR2GRAY) src = cv.GaussianBlur(src, (5, 5), 0) edges = cv.Canny(src, 50, 150, None, 3) lines = cv.HoughLinesP(edges, 1, np.pi / 180, 50, None, min_length, 10) horz_lines = [] vert_lines = [] for ls in lines: x1, y1, x2, y2 = ls[0] if y1 == y2: horz_lines.append(y1) elif x1 == x2: vert_lines.append(x1) horz_lines = uniq_lines(horz_lines) vert_lines = uniq_lines(vert_lines) return [horz_lines, vert_lines] def clear_rect(img, rect): "清除img中rect指定的区域图像" x, y, w, h = rect img[y:y+h, x:x+w] = 255 return img def best_grid_size(grids): "返回最合适的grid大小" items = grids[0] diffs = [x-y for x, y in zip(items[1:], items[:-1])] items2 = grids[1] diffs2 = [x-y for x, y in zip(items2[1:], items2[:-1])] c = Counter(diffs+diffs2) return c.most_common(1)[0][0] def make_grid_pos(length, grid_size): '''根据网格大小生成网格线位置''' return [i*grid_size for i in range(int(length/grid_size)+1)] def find_grid_lines(img, start_rect, end_rect, min_length=50): "查找图片的网格线" img2 = img.copy() img2 = clear_rect(img2, start_rect) img2 = clear_rect(img2, end_rect) grids = find_lines(img2, min_length) grid_size = best_grid_size(grids) y, x, _ = img.shape hls = make_grid_pos(y, grid_size) vls = make_grid_pos(x, grid_size) return [hls, vls] def show_grid(img, horz_lines, vert_lines): '''显示网格线''' ret = img.copy() for y in horz_lines: cv.line(ret, (0, y), (10000, y), (255, 0, 0), 2) for x in vert_lines: cv.line(ret, (x, 0), (x, 10000), (255, 0, 0), 2) cv.imwrite("show_grid.jpg", ret) cv.imshow("grid", ret) cv.waitKey(0) def in_thresh(source, target, thresh): '''是否在阈值范围内''' return target-thresh <= source <= target+thresh def count_range_color(img, x, y, width, height, color, color_thresh=40): '''统计矩形范围内指定颜色像素的个数''' count = 0 for i in range(width): for j in range(height): sb, sg, sr = img[y+j][x+i] tb, tg, tr = color if in_thresh(sb, tb, color_thresh) and in_thresh(sg, tg, color_thresh) and in_thresh(sr, tr, color_thresh): count += 1 return count
wall = (0, 0, 0) def fix_v(x, max_v): "修正x,使0 <= x <= max_v" x = min(x, max_v) x = max(0, x) return x def fix_x(img, x): return fix_v(x, img.shape[1]) def fix_y(img, y): return fix_v(y, img.shape[0]) def is_horz_wall(img, x, y, grid_size, precision=3): "是否是水平方向的墙 x,y为图片坐标, precision为选取测试的矩形范围,增强容错" w = int(grid_size / 2) h = precision*2 x = x + int(w/2) y = y - precision w = fix_x(img, x+w)-x h = fix_y(img, y+h)-y x = fix_x(img, x) y = fix_y(img, y) count = count_range_color(img, x, y, w, h, wall) logging.info(f"x:{x}, y:{y}, w:{w}, h:{h} count:{count}") if count >= w*0.8: return True return False def is_vert_wall(img, x, y, grid_size, precision=3): "是否是垂直方向的墙 x,y为图片坐标" w = precision*2 h = int(grid_size / 2) x = x - precision y = y + int(h/2) w = fix_x(img, x+w)-x h = fix_y(img, y+h)-y x = fix_x(img, x) y = fix_y(img, y) count = count_range_color(img, x, y, w, h, wall) logging.info(f"x:{x}, y:{y}, w:{w}, h:{h} count:{count}") if count >= h*0.8: return True return False def check_wall(img, grid_lines, x, y): "检测x,y指定格子四周是否有墙, 返回[上, 下, 左, 右]是否有墙的bool值" logging.info(f"check wall x:{x}, y:{y}") hls, vls = grid_lines grid_size = min(hls[1]-hls[0], vls[1]-vls[0]) left = vls[x] right = vls[fix_v(x+1, len(vls)-1)] top = hls[y] bottom = hls[fix_v(y+1, len(hls)-1)] logging.info(f"left:{left}, right:{right}, top:{top}, bottom:{bottom}") top_wall = is_horz_wall(img, left, top, grid_size) bottom_wall = is_horz_wall(img, left, bottom, grid_size) left_wall = is_vert_wall(img, left, top, grid_size) right_wall = is_vert_wall(img, right, top, grid_size) return [top_wall, bottom_wall, left_wall, right_wall] def find_in_range_pos(ranges, v): '''ranges必须为升序列表, 查找v在ranges中的第一个位置索引''' for idx, v2 in enumerate(ranges): if v2 >= v: return idx return None def find_grid_pos(img, grid_lines, x, y): "查找图像坐标x,y所在的格子" hls, vls = grid_lines x_pos = find_in_range_pos(vls, x) - 1 y_pos = find_in_range_pos(hls, y) - 1 return [x_pos, y_pos] def rect_center(rect): '''计算矩形中心点''' x, y, w, h = rect return [x+int(w/2), y+int(h/2)]
|