深度学习图片预处理:crop 您所在的位置:网站首页 数字3192什么意思 深度学习图片预处理:crop

深度学习图片预处理:crop

2024-07-03 22:24| 来源: 网络整理| 查看: 265

内容

1.前言

2.带注释代码

3.原理分析

前言

在深度学习中,经常需要将输入图片进行裁剪,转换为网络输入的图片height和width。如果直接将图片进行resize,可能使得图片中的bbox变形。因此需要对原图进行扩展之后,以原图的bbox中心作为输出图的中心,按照[height,width] × \times × c r o p _ s i z e m i n _ s h a p e \frac{crop\_size}{min\_shape} min_shapecrop_size​的大小进行裁剪,然后再resize到[height,width]进行输出。这样裁剪的好处是可以使得bbox不会变形。

带注释代码

原图(img),扩展后的图片(bimg),裁剪后的图片(crop_img)效果如下:

在这里插入图片描述

import cv2 import imageio import matplotlib.pyplot as plt import matplotlib.patches as patches import numpy as np is_train = True height, width = 256, 192 # 横 x 竖 y bbox = [111, 3, 390, 295] # x1,y1,x2,y2 # 1.ori img img = imageio.imread('test.jpg') add = max(img.shape[0], img.shape[1]) # 找出输入图片的最长边,等下在四周进行add大小的填充 mean_value = [122.7717, 115.9465, 102.9801] # 2.border img bimg = cv2.copyMakeBorder(img, add, add, add, add, borderType=cv2.BORDER_CONSTANT, # constant pixel_mean as border value=mean_value) #四周填充上add后的图像为bimg bbox = np.array(bbox).reshape(4, ).astype(np.float32) # bbox contains obj objcenter = np.array([(bbox[0] + bbox[2]) / 2., # bbox_w/2 (bbox[1] + bbox[3]) / 2.]) # bbox_h/2 #找出bbox的中心点的坐标 # 此处将bbox,keypoints等调整为bimg中的坐标 bbox += add # bbox由原图调整为bimg中的坐标 objcenter += add #bbox中心由原图调整为bimg中的坐标 # 3.extend and crop img bbox_extend_factor = (0.1, 0.15) # bbox [w,h] * (1 + extend_factor), [0.1, 0.15] crop_width = (bbox[2] - bbox[0]) * (1 + bbox_extend_factor[0] * 2) # 两边各扩展0.1倍bbox_extend_factor crop_height = (bbox[3] - bbox[1]) * (1 + bbox_extend_factor[1] * 2) if is_train: #训练情况下再进行一定扩展 crop_width = crop_width * (1 + 0.25) crop_height = crop_height * (1 + 0.25) print('image_wh:', img.shape[1], img.shape[0]) # width=533,height=330 print('input_wh:', width, height) # 192,256 print() print('ori_bbox_wh:', bbox[2] - bbox[0], bbox[3] - bbox[1]) # 279.0,292.0 print('crop_box_wh:', crop_width, crop_height) # 418.5,474.5 print('crop/input:', crop_width / width, crop_height / height) # 2.18,1.85 print() # crop_size 取比例较大的边,min_shape取边对应的输出边 if crop_height / height > crop_width / width: crop_size = crop_height min_shape = height else: crop_size = crop_width min_shape = width print('crop size:', crop_size) # 418.5 print('min shape:', min_shape) # 192 print() print('after extend') print('objcenter:', objcenter) # 783.5 682 print('crop bbox:', bbox) # [389. 387. 637. 558.] print('bimg_wh:', bimg.shape[1], bimg.shape[0]) # 1599 1366 print() # min_shape = height or width of input # crop_size 与 obj 左右上下 相比较 crop_size = min(crop_size, objcenter[0] / width * min_shape * 2. - 1.) # if width=min_shape, objcenter[0]*2-1 crop_size = min(crop_size, (bimg.shape[1] - objcenter[0]) / width * min_shape * 2. - 1) crop_size = min(crop_size, objcenter[1] / height * min_shape * 2. - 1.) crop_size = min(crop_size, (bimg.shape[0] - objcenter[1]) / height * min_shape * 2. - 1) # 以 crop_size 为基准,基于 objcenter 在 bimg 上获得 左上,右下 点 # 保证图像宽高比 = model input 宽高比,所以 x,y_ratio 是相等的 min_x = int(objcenter[0] - crop_size / 2. / min_shape * width) max_x = int(objcenter[0] + crop_size / 2. / min_shape * width) min_y = int(objcenter[1] - crop_size / 2. / min_shape * height) max_y = int(objcenter[1] + crop_size / 2. / min_shape * height) x_ratio = float(width) / (max_x - min_x) y_ratio = float(height) / (max_y - min_y) print('ratios:', x_ratio, y_ratio) crop_img = cv2.resize(bimg[min_y:max_y, min_x:max_x, :], (width, height)) #显示图片 plt.subplot(2,2,1) plt.imshow(img) plt.gca().add_patch( patches.Rectangle(xy=(bbox[0], bbox[1]), # bottom, left width=bbox[2] - bbox[0], height=bbox[3] - bbox[1], linewidth=1, edgecolor='r', facecolor='none')) plt.subplot(2,2,2) plt.imshow(bimg) plt.gca().add_patch( patches.Rectangle(xy=(bbox[0], bbox[1]), # bottom, left width=bbox[2] - bbox[0], height=bbox[3] - bbox[1], linewidth=1, edgecolor='r', facecolor='none')) plt.subplot(2,2,3) plt.imshow(crop_img) plt.show() 原理分析

1.首先为了确保最后resize的时候bbox能全部裁剪进去,所以要先对bbox进行适当扩展。

2.由于最终resize之后的[height,width]确定,所以需要确定的就是放缩的系数 c r o p _ s i z e m i n _ s h a p e \frac{crop\_size}{min\_shape} min_shapecrop_size​。

先来理解这一段代码。

# crop_size 取比例较大的边,min_shape取边对应的输出边 if crop_height / height > crop_width / width: crop_size = crop_height min_shape = height else: crop_size = crop_width min_shape = width

可以看到相当于是粗略的选择了一下放缩系数 c r o p _ s i z e m i n _ s h a p e \frac{crop\_size}{min\_shape} min_shapecrop_size​。那么为什么要选择比例较大的边呢,我个人认为可以这么理解,假设一个情况。假若crop_height很大,crop_width很小,而height很小,width很大,那么如果我们选择比例较小的边,那就是crop_width / width作为放缩系数 c r o p _ s i z e m i n _ s h a p e \frac{crop\_size}{min\_shape} min_shapecrop_size​,根据假设可以得出这个放缩系数小于1。

由下面代码可以看出,在bimg上裁剪的时候,是以[height,width] × \times × c r o p _ s i z e m i n _ s h a p e \frac{crop\_size}{min\_shape} min_shapecrop_size​的大小进行裁剪的,如果放缩系数小于1,height本身很小,crop_height很大,就会使得height × \times × c r o p _ s i z e m i n _ s h a p e \frac{crop\_size}{min\_shape} min_shapecrop_size​比crop_height小很多。这样将导致裁剪的时候bbox会丢失很多在height方向上的图片信息。

min_x = int(objcenter[0] - crop_size / 2. / min_shape * width) max_x = int(objcenter[0] + crop_size / 2. / min_shape * width) min_y = int(objcenter[1] - crop_size / 2. / min_shape * height) max_y = int(objcenter[1] + crop_size / 2. / min_shape * height)

因此粗略的确定 c r o p _ s i z e m i n _ s h a p e \frac{crop\_size}{min\_shape} min_shapecrop_size​这个系数需要选择比例较大的边。

3.后面部分就是关于 c r o p _ s i z e m i n _ s h a p e \frac{crop\_size}{min\_shape} min_shapecrop_size​的一个调整了。

关于调整主要需要关注三个方面的内容,第一个, c r o p _ s i z e m i n _ s h a p e \frac{crop\_size}{min\_shape} min_shapecrop_size​需要保证区域大小完全在bimg之内,这个很显然,如果超出了bimg区域,怎么来裁剪呢;第二个 c r o p _ s i z e m i n _ s h a p e \frac{crop\_size}{min\_shape} min_shapecrop_size​需要保证完全包括了bbox的所有区域;第三个, c r o p _ s i z e m i n _ s h a p e \frac{crop\_size}{min\_shape} min_shapecrop_size​需要尽量小,因为在完全包括bbox的前提下,放缩系数越大,resize之后的bbox区域就会越模糊。

由于是同左右上下进行比较,所以我只取同左边进行比较相关的代码,其余可以以此类推。下面一个一个来看代码是怎么来满足这三个方面的。

crop_size = min(crop_size, objcenter[0] / width * min_shape * 2. - 1.) min_x = int(objcenter[0] - crop_size / 2. / min_shape * width)

第一个:

假如crop_size crop_width / width时。此时H=crop_size,满足H>bbox_height,所以在height上满足第二个要求,同时有W=width × \times × c r o p _ s i z e m i n _ s h a p e \frac{crop\_size}{min\_shape} min_shapecrop_size​>width × \times × c r o p _ w i d t h w i d t h \frac{crop\_width}{width} widthcrop_width​=crop_width,所以在width上满足第二个要求。

当min(crop_size, objcenter[0] / width * min_shape * 2. - 1.)=objcenter[0] / width * min_shape * 2. - 1时,

有W=width × \times × c r o p _ s i z e m i n _ s h a p e \frac{crop\_size}{min\_shape} min_shapecrop_size​=width × \times × ( o b j c e n t e r [ 0 ] ∗ 2 / w i d t h − 1 m i n _ s h a p e ) (objcenter[0] * 2/ width-\frac{1}{min\_shape}) (objcenter[0]∗2/width−min_shape1​)。

现在比较 ( o b j c e n t e r [ 0 ] ∗ 2 / w i d t h − 1 m i n _ s h a p e ) (objcenter[0] * 2/ width-\frac{1}{min\_shape}) (objcenter[0]∗2/width−min_shape1​)和 c r o p _ w i d t h w i d t h \frac{crop\_width}{width} widthcrop_width​的 大小关系。经过变换,等于比较

( o b j c e n t e r [ 0 ] ∗ 2 − w i d t h m i n _ s h a p e ) (objcenter[0] * 2-\frac{width}{min\_shape}) (objcenter[0]∗2−min_shapewidth​)和crop_width的关系。因为objcenter[0] * 2等价于bimg中bbox中心以左部分长度的两倍。add = max(img.shape[0], img.shape[1]),add>=bbox_width,而可以从下面的代码可以看出crop_widthcrop_width

bbox_extend_factor = (0.1, 0.15) crop_width = (bbox[2] - bbox[0]) * (1 + bbox_extend_factor[0] * 2)

而 w i d t h m i n _ s h a p e \frac{width}{min\_shape} min_shapewidth​是一个很小的量,所以可以不太严谨地证明出 ( o b j c e n t e r [ 0 ] ∗ 2 − w i d t h m i n _ s h a p e ) (objcenter[0] * 2-\frac{width}{min\_shape}) (objcenter[0]∗2−min_shapewidth​)大于crop_width。所以有W=width × \times × ( o b j c e n t e r [ 0 ] ∗ 2 / w i d t h − 1 m i n _ s h a p e ) (objcenter[0] * 2/ width-\frac{1}{min\_shape}) (objcenter[0]∗2/width−min_shape1​)>width × \times × c r o p _ w i d t h w i d t h \frac{crop\_width}{width} widthcrop_width​=crop_width,所以在width上满足第二个要求。

第三个:

由前面的证明得到了crop_size及左右上下的部分,都满足第一个和第二个要求。那么下面这一段代码其实就是在寻找满足第三个要求的过程,即找到尽量小的 c r o p _ s i z e m i n _ s h a p e \frac{crop\_size}{min\_shape} min_shapecrop_size​。

crop_size = min(crop_size, objcenter[0] / width * min_shape * 2. - 1.) crop_size = min(crop_size, (bimg.shape[1] - objcenter[0]) / width * min_shape * 2. - 1) crop_size = min(crop_size, objcenter[1] / height * min_shape * 2. - 1.) crop_size = min(crop_size, (bimg.shape[0] - objcenter[1]) / height * min_shape * 2. - 1)

到这里为止,我们对代码进行了分析,理解了代码为什么这么写的原理,数据预处理里面crop的部分算是大功告成啦(撒花)。

以上都是个人的理解和推导过程,转载请注明出处,要是有错误或考虑不周的地方欢迎指出。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有