opencv轮廓检测后裁剪图片

本文最后更新于:2023年2月9日 上午

目的是提高数字在图片中的占比,先用边缘检测找到数字的轮廓,然后得到最小矩形框,再裁剪图片

效果

原始图像为完全透明背景的数字,效果如下:

处理后的图将背景变为不透明的白色,然后裁剪掉周围的空白,大小变为28X28

代码

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
import cv2
import numpy as np

def detCut(imgPath,savePath="./result"):
# 将透明背景图片转换为白色背景
image = cv2.imread(imgPath,-1)
if(len(image[0,0]) >= 4):
image[image[:,:,3]==0] = [255,255,255,255]
# else:
# print("不是RGBA,不进行透明度处理")
# 将图片转为单通道
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 边缘检测
edges = cv2.Canny(gray, 0, 100)
contours,hierarchy = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# 得到矩形框
allarea = np.concatenate(contours)#合并所有轮廓点集合
rect = cv2.minAreaRect(allarea) # 获取最小矩形
box = np.int0(cv2.boxPoints(rect)) # 通过box会出矩形框
# 坐标最大值
max_x = np.max(box[:, 0])
max_y = np.max(box[:, 1])
# 坐标最小值
min_x = np.min(box[:, 0])
min_y = np.min(box[:, 1])
# 坐标偏移
offset = 2
# 裁剪
crop_img = image[min_y - offset:max_y + offset, min_x - offset:max_x + offset]
# 改变大小
crop_img = cv2.resize(crop_img, (28, 28))
# cv2.imshow("22222", image)
# cv2.imshow("crop_img", crop_img)
# cv2.waitKey(0)

# 查看文件夹是否存在
if not os.path.exists(savePath):
os.makedirs(savePath)
outName = imgPath.split("\\")[-1].split(".")[0] + "_result.jpg"
savePath = os.path.join(savePath,outName)
print("输出: {}".format(savePath))
cv2.imwrite(savePath,crop_img)

import os
# 将指定文件夹中图片全部转化
def changeImgFolder(ImgFolderPath,outPath):
for root, dirs, files in os.walk(ImgFolderPath):
for file in files:
if file.endswith(".png"):
#print(os.path.join(root, file))
detCut(os.path.join(root, file),outPath)


changeImgFolder("./testImg","./resultImg")

函数cv2.findContours(image, mode, method[, offset])

参数

image:单通道二值图,白色是前景
mode:轮廓检索的方式:

  • cv2.RETR_EXTERNAL:只检索外部轮廓
  • cv2.RETR_LIST: 检测所有轮廓且不建立层次结构
  • cv2.RETR_CCOMP: 检测所有轮廓,建立两级层次结构
  • cv2.RETR_TREE: 检测所有轮廓,建立完整的层次结构
    method:轮廓近似的方法
  • cv2.CHAIN_APPROX_NONE:存储所有的轮廓点
  • cv2.CHAIN_APPROX_SIMPLE:压缩水平,垂直和对角线段,只留下端点。 例如矩形轮廓可以用4个点编码。
  • cv2.CHAIN_APPROX_TC89_L1,cv2.CHAIN_APPROX_TC89_KCOS:使用Teh-Chini chain近似算法

返回值

contours:轮廓点。列表,每一个元素为一个3维数组(其形状为(n,1,2),其中n表示轮廓点个数,2表示像素点坐标),表示一个轮廓
hierarchy:轮廓间的层次关系,为三维数组,形状为(1,n,4),其中n表示轮廓总个数,4指的是用4个数表示各轮廓间的相互关系。第一个数表示同级轮廓的下一个轮廓编号,第二个数表示同级轮廓的上一个轮廓的编号,第三个数表示该轮廓下一级轮廓的编号,第四个数表示该轮廓的上一级轮廓的编号

函数cv2.getStructuringElement(shape,ksize)

参数

shape:核的形状

  • cv2.MORPH_RECT:矩形
  • cv2.MORPH_ELLIPSE:椭圆
  • cv2.MORPH_CROSS:十字形
    ksize:核的大小

返回值

函数cv2.erode

腐蚀,去毛刺
传入三个参数,图、核、迭代次数
cv2.erode(binary, erode_kernel, iterations=1)

函数cv2.dilate

膨胀便圆润
传入三个参数,图、核、迭代次数
cv2.dilate(erosion, dilation_kernel, iterations = 1)

函数cv2.threshold(src, thresh, maxval, type[, dst])

根据设定的值处理图像的灰度值,例如大于设定值就保留或者修改
src:是灰度图像
thresh:起始阈值
maxval:是最大值
type:处理方式,有如下类型

  • cv2.THRESH_BINARY:大于阈值的像素点赋值为maxval,小于阈值的像素点赋值为0
  • cv2.THRESH_BINARY_INV:大于阈值的像素点赋值为0,小于阈值的像素点赋值为maxval
  • cv2.THRESH_TRUNC:大于阈值的像素点赋值为thresh,小于阈值的像素点不变
  • cv2.THRESH_TOZERO:大于阈值的像素点不变,小于阈值的像素点赋值为0
  • cv2.THRESH_TOZERO_INV:大于阈值的像素点赋值为0,小于阈值的像素点不变

返回值:ret,thresh1
ret:阈值
thresh1:处理后的图像


opencv轮廓检测后裁剪图片
https://blog.kala.love/posts/ee7b39c3/
作者
Lissettecarlr
发布于
2023年2月3日
许可协议