目录????????????
- 中心外扩的最佳RoI(裁图)
- 根据两个坐标点求缩放+偏移后的RoI
- 自定义RGB2BGR颜色解析小函数
- 滑窗切片(sliding window crops)
- VOC的颜色+调色板
中心外扩的最佳RoI(裁图)
指定中心点和裁图宽高,获得裁图位置xyxy坐标(最佳),便于在图像裁剪。
def get_best_crop_position_of_center(center_xy, img_w, img_h, crop_w, crop_h):
pt = center_xy
x0, y0 = max(0, pt[0] - crop_w // 2), max(0, pt[1] - crop_h // 2) # 左上角 >= (0,0)
x1, y1 = min(x0 + crop_w, img_w), min(y0 + crop_h, img_h) # 右下角
return [int(x1-crop_w), int(y1-crop_h), int(x1), int(y1)]
根据两个坐标点求缩放+偏移后的RoI
def get_xyxy_scale_shift(pt1, pt2, scale_xy=1.0, shift=0, imgW=0, imgH=0):
"""
给定两个坐标点,返回缩放+偏移后的RoI坐标
:param pt1, pt2: 两个坐标点
:param scale_xy: 缩放比例,还原到原图
:param shift: 短边的放大偏移量(长边不变)
:param imgW: RoI坐标限宽
:param imgH: RoI坐标限高
"""
x0, y0, x1, y1 = min(pt1[0], pt2[0]), min(pt1[1], pt2[1]), max(pt1[0], pt2[0]), max(pt1[1], pt2[1]) # 左上, 右下
x0, y0, x1, y1 = round(x0 * scale_xy), round(y0 * scale_xy), round(x1 * scale_xy), round(y1 * scale_xy) # 缩放,取整
if x1 - x0 == y1 - y0:
x0, x1 = x0 - shift, x1 + shift
y0, y1 = y0 - shift, y1 + shift
elif x1 - x0 < y1 - y0:
x0, x1 = x0 - shift, x1 + shift
else:
y0, y1 = y0 - shift, y1 + shift
if imgW > 0:
x0 = min(max(0, x0), imgW)
x1 = min(max(0, x1), imgW)
if imgH > 0:
y0 = min(max(0, y0), imgH)
y1 = min(max(0, y1), imgH)
return int(x0+0.5), int(y0+0.5), int(x1+0.5), int(y1+0.5)
上面函数可以应用在图像上画矩形框,
def draw_RoI(img: np.ndarray, pt1, pt2, scale_xy=1.0, shift=0, color=None, thickness=None):
if color is None: color = (0,255,0)
imgH, imgW = img.shape[:2]
x0, y0, x1, y1 = get_xyxy_scale_shift(pt1, pt2, scale_xy, shift, imgW, imgH)
cv2.rectangle(img, (x0, y0), (x1, y1), color, thickness)
return x0, y0, x1, y1
自定义RGB2BGR颜色解析小函数
def rgb2bgr(rgb):
if isinstance(rgb, (list, tuple)):
rgb_list = []
for val in rgb:
if isinstance(val, str) and val.strip() != '':
rgb_list.append(int(val.strip()))
elif isinstance(val, int):
rgb_list.append(val)
return rgb_list[::-1]
elif isinstance(rgb, str):
bgr = [int(val.strip()) for val in rgb.split(',') if val.strip() != ''][::-1]
return bgr
else:
raise ValueError("error in converting RGB[" + str(rgb) + "] to BGR")
滑窗切片(sliding window crops)
指定横向和纵向的Windows数,自适应计算每个Window的宽和高,以及滑窗步长,居中对齐,返回每个Window的坐标。
def make_grids(img, grid_x, grid_y, dx=0, dy=0):
"""
make grids in x-axis and y-axis
指定横向和纵向的Windows数,自适应计算每个Window的宽和高,居中对齐,返回每个Window的坐标
Args:
img: ndarray
grid_x: number of grids in x-axis,指定横向窗口数
grid_y: number of grids in y-axis,指定纵向窗口数
dx: shrinking size in x-axis,横向窗口间隔的一半
dy: shrinking size in y-axis,纵向窗口间隔的一半
Returns:
[[grid_box]], where
grid_box = (upleft_pt, downright_pt) = ((x0, y0), (x1, y1))
"""
grid_boxs = []
h, w = img.shape[:2]
left_pad, up_pad = (w % grid_x) // 2, (h % grid_y) // 2
box_w, box_h = w // grid_x, h // grid_y
for hi in range(grid_y):
row_boxs = [((left_pad+wi*box_w+dx, up_pad+hi*box_h+dy),
(left_pad+(wi+1)*box_w-dx, up_pad+(hi+1)*box_h-dy))
for wi in range(grid_x)]
grid_boxs.append(row_boxs)
return grid_boxs
def make_grids_sliding(img, grid_x, grid_y, box_w, box_h):
"""
指定横向和纵向的Windows数 以及窗口大小,有overlapping的滑窗,左右上下紧贴边
Args:
img: ndarray
grid_x: number of grids in x-axis,指定横向窗口数
grid_y: number of grids in y-axis,指定纵向窗口数
box_w: width of each box,窗口横向宽度
box_h: height of each box,窗口纵向高度
Returns:
[[grid_box]], where
grid_box = (upleft_pt, downright_pt) = ((x0, y0), (x1, y1))
Examples:
[:append]
grid_boxs = make_grids_sliding(srcImg, 4, 3, 1280, 1280)
for idy, row_boxs in enumerate(grid_boxs):
for idx, ((x0, y0), (x1, y1)) in enumerate(row_boxs):
cv2.circle(srcImg, ((x0+x1)//2, (y0+y1)//2), 20, color, -1)
[:extend]
grid_boxs = make_grids_sliding(srcImg, 4, 3, 1280, 1280)
for (x0, y0), (x1, y1) in grid_boxs:
cv2.circle(srcImg, ((x0+x1)//2, (y0+y1)//2), 20, color, -1)
"""
grid_boxs = []
h, w = img.shape[:2]
# box_h, box_w = min(h, box_h), min(w, box_w) # 保证:窗口大小 <= 原图大小
lt_x0y0, rd_x0y0 = (0, 0), (max(0, w-box_w), max(0, h-box_h)) # 左上角窗口、右下角窗口的左上角坐标
x0linspace = [int(x0) for x0 in np.linspace(lt_x0y0[0], rd_x0y0[0], grid_x)]
y0linspace = [int(y0) for y0 in np.linspace(lt_x0y0[1], rd_x0y0[1], grid_y)]
for y0 in y0linspace:
row_boxs = [((x0, y0), (x0+box_w, y0+box_h))
for x0 in x0linspace] # 左上角、右下角
grid_boxs.extend(row_boxs) # .append
return grid_boxs
if __name__ == '__main__':
srcImg = np.zeros((2000, 2000, 3), dtype=np.uint8)
grid_boxs = make_grids_sliding(srcImg, 2, 2, 1280, 1280)
print(grid_boxs)
# 在crop_srcImg上滑动窗口裁图,将grid_boxs从crop_srcImg映射回srcImg
px0, py0 = 10, 10
for idy, row_boxs in enumerate(grid_boxs):
(x0, y0), (x1, y1) = row_boxs
grid_boxs[idy] = ((x0 + px0, y0 + py0), (x1 + px0, y1 + py0))
print(grid_boxs)
VOC的颜色+调色板
通过位运算,巧妙地生成有梯度(相差128个灰度值)的RGB颜色表,相比打表可快多了。
def create_pascal_label_colormap():
"""
PASCAL VOC 分割数据集的类别标签颜色映射label colormap
返回:
可视化分割结果的颜色映射Colormap
Examples:
colormap = create_pascal_label_colormap()
color = colormap[idx].tolist() # [b, g, r]
# 分割结果label.shape=(1024,1024),渲染图vis.shape=(1024,1024,3)
vis = colormap[label]
"""
colormap = np.zeros((256, 3), dtype=int)
ind = np.arange(256, dtype=int)
for shift in reversed(range(8)):
for channel in range(3):
colormap[:, channel] |= ((ind >> channel) & 1) << shift
ind >>= 3
return colormap