python利用图像处理方法 实现多目标检测与裁剪(opencv)

图像处理方法实现多目标检测与裁剪

  • 简述
    • 1.批量resize
      • 1)效果
      • 2)原理
      • 3)代码分析
    • 2.找出所有目标轮廓(定位)
      • 1)效果
      • 2)原理
      • 3)代码分析
    • 3.确定裁剪区域
      • 1)效果
      • 2)原理
      • 3)代码分析
  • 源代码

简述

对于一些特殊多目标图像,例如细粒度目标、缺乏标注文件等。或是图像前背景区分较明显的图像,不适合用深度学习模型进行目标定位与分割。相比之下,利用较为传统的图像处理方式,可以更高效地实现对上述图像的目标定位与分割(抠图)。
本文将分为三个部分详细讲解利用opencv对多目标图像进行目标定位与分割的实现过程。

1.批量resize

先对目标文件夹下所有图片进行resize,将所有图片resize到同一大小,方便后续进行批量操作。

1)效果

原图:python利用图像处理方法 实现多目标检测与裁剪(opencv)_第1张图片
resize后的图像:
python利用图像处理方法 实现多目标检测与裁剪(opencv)_第2张图片

将图片resize成800×800,原图为502×502。

2)原理

先利用os.listdir方法将目标文件夹下的所有图像读取出来,再分别根据图像的宽高等比例地将图像resize成目标大小。最后利用opencv的imwrite()方法批量保存resize后的图片。

3)代码分析

  1. 利用for循环将目标文件夹下所有图片读取出来。
for i in os.listdir(imgs_p):
    img_path=os.path.join(imgs_p,i)
    img = cv2.imread(img_path)
  1. 与原图等比例进行resisze
	height, width = img.shape[:2]  # 得到行和列的长度
    scale=size/height  # 得到size和图像高的缩放比例
    height=size
    width=int(width*scale)
    img = cv2.resize(img, (width, height))
  1. 批量保存
	new_img_path=os.path.join(imgs_save_p,i)
    cv2.imwrite(new_img_path,img)

2.找出所有目标轮廓(定位)

1)效果

python利用图像处理方法 实现多目标检测与裁剪(opencv)_第3张图片

2)原理

试验过多种方式(包括阈值分割、边缘分割等)最后选用网上流传度最高的xy方向梯度相减方式进行分割。
读取图片,先将图片转换成灰度图,分别计算x方向和y方向的梯度,然后对其相减,留下具有高水平梯度和低垂直梯度的图像区域。
之后去除噪声,再进行二值化,最后确定目标轮廓。

3)代码分析

  1. 批量读取图片,得到图像的宽和高,将图像转为灰度图,利用sobel算子分别计算x、y轴方向上的一阶梯度值,相减。
	image = cv2.imread(img_path)
    shape = image.shape
    image_row = shape[0]
    image_col = shape[1]
    print(image_row,image_col)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # 得到灰度图
    gradX = cv2.Sobel(gray, ddepth=cv2.CV_32F, dx=1, dy=0, ksize=-1) # x方向一阶导数
    gradY = cv2.Sobel(gray, ddepth=cv2.CV_32F, dx=0, dy=1, ksize=-1) # y方向一阶导数
    gradient = cv2.subtract(gradX, gradY)
  1. 利用低通滤波器对图像进行去噪,再将图像转化为二值图,最后利用膨胀和侵蚀得到下图,利用下图描出的轮廓即可确定原图目标位置。
    python利用图像处理方法 实现多目标检测与裁剪(opencv)_第4张图片
	blurred = cv2.blur(gradient, (9, 9))  # 滤波,去除噪声
    (_, thresh) = cv2.threshold(blurred, 20, 255, cv2.THRESH_BINARY)    # 图像二值化,thresh为得到的图像
    thresh = cv2.erode(thresh, None, iterations=5)
    thresh = cv2.dilate(thresh, None, iterations=4)
  1. 利用opencv的findcounter函数找到所有轮廓。
	(cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)  # cnts为得到的轮廓,存放在一个list中
    all_box_img = copy.deepcopy(image)  # 深复制,跟原图没有关系,一个改变不影响另一个
    cv2.drawContours(all_box_img, cnts, -1, (0, 255, 0), 1)  # 在all_box_img上画轮廓

3.确定裁剪区域

1)效果

裁剪区域:
python利用图像处理方法 实现多目标检测与裁剪(opencv)_第5张图片
单个目标:
python利用图像处理方法 实现多目标检测与裁剪(opencv)_第6张图片python利用图像处理方法 实现多目标检测与裁剪(opencv)_第7张图片
python利用图像处理方法 实现多目标检测与裁剪(opencv)_第8张图片

python利用图像处理方法 实现多目标检测与裁剪(opencv)_第9张图片

2)原理

利用cv2.minAreaRect函数确定目标的最小外接矩形。再将区域resize成与x、y轴平行的样式,最后选定区域进行裁剪并保存。

3)代码分析

  1. 只保留面积符合尺寸要求的目标(这一部分读者自行更改)
	for i, contour in enumerate(cnts):
        area = cv2.contourArea(contour)  # 计算包围形状的面积
        if area < 550:  # 过滤面积小于550的部分
            continue
  1. 检测目标最小外接矩形
	rect = cv2.minAreaRect(contour)  # 检测轮廓最小外接矩形,得到最小外接矩形的(中心(x,y), (宽,高), 旋转角度)
    box = np.int0(cv2.boxPoints(rect))
    boxs.append(box)   # 最后剩下的有用的框
  1. 进行裁剪
for i,box in enumerate(boxs):  # 裁剪
        xs = [j[0] for j in boxs[i]]
        ys = [j[1] for j in boxs[i]]
        x1 = min(xs)
        x2 = max(xs)
        y1 = min(ys)
        y2 = max(ys)
        if x1 < 0:
            x1 = 0
        if x2 > image_col:
            x2 = image_col
        if y1 < 0:
            y1 = 0
        if y2 > image_row:
            y2 = image_row
        print(x1,x2,y1,y2)
        hight = y2 - y1
        width = x2 - x1

源代码

  • 详细源代码

你可能感兴趣的:(opencv,目标检测,opencv,图像处理,python,数据分析)