《LearnPython-Python学习笔记》-pythonopencv图像处理(提取矩形方框提取颜色滤波轮廓检测直线检测)

admin 2025-11-07 01:27:13 编程 来源:ZONE.CI 全球网 0 阅读模式
  • 一、依赖
    • 3、完整代码

    一、依赖

    如果你的python环境没有这些包,则需要安装

    1. pip install numpy opencv-python pillow

    二、使用指南1、基本信息近期由于项目需要,需要使用python的opencv库处理图像,在下面的代码中使用了很多cv2的库函数,对这些函数进行了封装,可以直接拷贝调用.项目地址该部分有两个文件构成 main.py 和  replace.py运行main.py可读取文件夹下的图像,提取图像格子中的字母并保存到本地2、图像处理流程原图如下: image.pngHSV特定颜色提取separate_color_red 提取图像中的红色框线用HSV提取红色部分,查看HSV颜色分量范围[点击此处](https://blog.csdn.net/u013270326/article/details/80704754))参数解释: cv2.inRange(hsv, lowerb=lower_hsv, upperb=high_hsv)第一个参数为输入图像,图像格式必须转为HSV格式,可通过cv2.cvtColor()转换第二个参数分别为H,S,V的最低值第三个参数分别为H,S,V的最高值

    1. hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 色彩空间转换为hsv,便于分离
    2. lower_hsv = np.array([0, 43, 46]) # 提取颜色的低值
    3. high_hsv = np.array([10, 255, 255]) # 提取颜色的高值
    4. mask = cv2.inRange(hsv, lowerb=lower_hsv, upperb=high_hsv)

    效果如下:image.png

    • 中值滤波

    medianBlur 中值滤波,过滤除最外层框线以外的线条参数解释:cv2.medianBlur(img,19)第一个参数:输入的图像第二个参数:滤波模板的尺寸大小,必须是大于1的奇数,如3、5、7

    1. mediu = cv2.medianBlur(img,19)

    效果如下:image.pngHoughLinesP概率霍夫变换直线检测调用直线检测函数需要先执行边缘检测函数,函数返回二值化图像参数解释:cv2.Canny(img, 20, 250)第一个参数:输入图像第二个参数:阀值1,用于将这些间断的边缘连接起来第三个参数:阀值2,用于检测图像中明显的边缘参数解释:cv2.HoughLinesP(img, 1, np.pi / 180, 120, line, minLineLength,maxLineGap)第一个参数:输入图像,必须为先用Canny边缘检测的图像第二个参数:直线的半径,建议选1第三个参数:步长为π/180的角来搜索所有可能的直线第五个参数:线的最短长度,比这个线短的都会被忽略第六个参数:两条线之间的最大间隔,如果小于此值,这两条线就会被看成一条线

    1. # 直线检测
    2. img2 = cv2.Canny(img, 20, 250) #边缘检测
    3. line = 4
    4. minLineLength = 50
    5. maxLineGap = 150
    6. # HoughLinesP函数是概率直线检测,注意区分HoughLines函数
    7. lines = cv2.HoughLinesP(img2, 1, np.pi / 180, 120, lines=line, minLineLength=minLineLength,maxLineGap=maxLineGap)
    8. lines1 = lines[:, 0, :] # 降维处理
    9. # line 函数勾画直线
    10. # (x1,y1),(x2,y2)坐标位置
    11. # (0,255,0)设置BGR通道颜色
    12. # 2 是设置颜色粗浅度
    13. for x1, y1, x2, y2 in lines1:
    14. cv2.line(img, (x1, y1), (x2, y2), (255, 255, 255), 2)

    findContours轮廓检测轮廓检测,获取最外层矩形框的偏转角度angle

    参数解释:image, contours, hier = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    第一个参数:二值化的图像,可以调用如下函数转为二值化图像

    1. cv2.threshold(cv2.cvtColor(img, 127, 255, cv2.THRESH_BINARY))

    第二个参数:表示轮廓的检索模式,有四种:cv2.RETR_EXTERNAL表示只检测外轮廓cv2.RETR_LIST检测的轮廓不建立等级关系cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息cv2.RETR_TREE建立一个等级树结构的轮廓。第三个参数:cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标.下面的代码对检测到的轮廓进行了筛选.并返回轮廓矩形坐标或倾斜角度

    1. #检测轮廓
    2. # ret, thresh = cv2.threshold(cv2.cvtColor(img, 127, 255, cv2.THRESH_BINARY))
    3. image, contours, hier = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    4. for c in contours: #遍历轮廓
    5. rect = cv2.minAreaRect(c) #生成最小外接矩形
    6. box_ = cv2.boxPoints(rect)
    7. h = abs(box_[3, 1] - box_[1, 1])
    8. w = abs(box_[3, 0] - box_[1, 0])
    9. print("宽,高",w,h)
    10. #只保留需要的轮廓
    11. if (h > 3000 or w > 2200):
    12. continue
    13. if (h < 2500 or w < 1500):
    14. continue
    15. box = cv2.boxPoints(rect) # 计算最小面积矩形的坐标
    16. box = np.int0(box) # 将坐标规范化为整数
    17. angle = rect[2] #获取矩形相对于水平面的角度
    18. if angle > 0:
    19. if abs(angle) > 45:
    20. angle = 90 - abs(angle)
    21. else:
    22. if abs(angle) > 45:
    23. angle = (90 - abs(angle))
    24. # 绘制矩形
    25. # cv2.drawContours(img, [box], 0, (255, 0, 255), 3)
    26. print("轮廓数量", len(contours))

    rotate 旋转图像至水平方向参数解释:cv2.getRotationMatrix2D(center, angle, 1)第一个参数:旋转图像的基点,这里同过获取图像的宽高计算中心点第二个参数:旋转角度第三个参数:图像缩放因子参数解释:cv2.warpAffine(img, img_ratete, (w, h))第一个参数:原图像第二个参数:从getRotationMatrix2D得到的图像第三个参数:图像大小

    1. (h, w) = img.shape[:2] #获得图片高,宽
    2. center = (w // 2, h // 2) #获得图片中心点
    3. img_ratete = cv2.getRotationMatrix2D(center, angle, 1)
    4. rotated = cv2.warpAffine(img, img_ratete, (w, h))

    效果如下:image.png

    • cut1 通过图像坐标从外层矩形框处裁剪原图

    image.png

    • 裁剪图片裁剪图片可通过数组切片操作完成,进行此操作打开图像必须用cv2.imiread(“path”)加载图像 ```python img[y1:y2, x1:x2] #切片裁剪图像
    1. 效果如图:<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/238239/1633711254357-d30e68df-d1ae-4d20-a134-7bcb15848617.png#clientId=u533588fb-dfcb-4&from=paste&id=uf03b987e&margin=%5Bobject%20Object%5D&name=image.png&originHeight=680&originWidth=724&originalType=url&ratio=1&size=99875&status=done&style=none&taskId=ube9fbcf1-4b4a-419f-90a4-58f9e184f2b)
    2. - **replace 消除多余红色框线**<br />如下代码可实现特定像素的替换,这个把红色替换为白色,进行此操作打开图像必须用PIL库函数Image.open(“path”)加载图像
    3. ```python
    4. img2 = Image.open(path3)
    5. img2 = img2.convert('RGBA') # 图像格式转为RGBA
    6. pixdata = img2.load()
    7. for y in range(img2.size[1]):
    8. for x in range(img2.size[0]):
    9. if pixdata[x, y][0] > 220: # 红色像素
    10. pixdata[x, y] = (255, 255, 255, 255) # 替换为白色,参数分别为(R,G,B,透明度)
    11. img2 = img2.convert('RGB') # 图像格式转为RGB
    12. print("替换文件",pathd)
    13. img2.save(path3)

    效果如图:image.png

    3、完整代码

    1. #main.py
    2. import cv2
    3. import numpy as np
    4. import os
    5. import replace
    6. def separate_color_red(img):
    7. #颜色提取
    8. # gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    9. hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 色彩空间转换为hsv,便于分离
    10. lower_hsv = np.array([0, 43, 46]) # 提取颜色的低值
    11. high_hsv = np.array([10, 255, 255]) # 提取颜色的高值
    12. mask = cv2.inRange(hsv, lowerb=lower_hsv, upperb=high_hsv)
    13. print("颜色提取完成")
    14. return mask
    15. def salt(img, n):
    16. #椒盐去燥
    17. for k in range(n):
    18. i = int(np.random.random() * img.shape[1])
    19. j = int(np.random.random() * img.shape[0])
    20. if img.ndim == 2:
    21. img[j, i] = 255
    22. elif img.ndim == 3:
    23. img[j, i, 0] = 255
    24. img[j, i, 1] = 255
    25. img[j, i, 2] = 255
    26. print("去燥完成")
    27. return img
    28. def show(name, img):
    29. #显示图片
    30. cv2.namedWindow(str(name), cv2.WINDOW_NORMAL)
    31. cv2.resizeWindow(str(name), 800, 2000) # 改变窗口大小
    32. cv2.imshow(str(name), img)
    33. def lines(img):
    34. # 直线检测
    35. img2 = cv2.Canny(img, 20, 250) #边缘检测
    36. line = 4
    37. minLineLength = 50
    38. maxLineGap = 150
    39. # HoughLinesP函数是概率直线检测,注意区分HoughLines函数
    40. lines = cv2.HoughLinesP(img2, 1, np.pi / 180, 120, lines=line, minLineLength=minLineLength,maxLineGap=maxLineGap)
    41. lines1 = lines[:, 0, :] # 降维处理
    42. # line 函数勾画直线
    43. # (x1,y1),(x2,y2)坐标位置
    44. # (0,255,0)设置BGR通道颜色
    45. # 2 是设置颜色粗浅度
    46. for x1, y1, x2, y2 in lines1:
    47. cv2.line(img, (x1, y1), (x2, y2), (255, 255, 255), 2)
    48. return img
    49. def contour(img):
    50. #检测轮廓
    51. # ret, thresh = cv2.threshold(cv2.cvtColor(img, 127, 255, cv2.THRESH_BINARY))
    52. image, contours, hier = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    53. for c in contours: #遍历轮廓
    54. rect = cv2.minAreaRect(c) #生成最小外接矩形
    55. box_ = cv2.boxPoints(rect)
    56. h = abs(box_[3, 1] - box_[1, 1])
    57. w = abs(box_[3, 0] - box_[1, 0])
    58. print("宽,高",w,h)
    59. #只保留需要的轮廓
    60. if (h > 3000 or w > 2200):
    61. continue
    62. if (h < 2500 or w < 1500):
    63. continue
    64. box = cv2.boxPoints(rect) # 计算最小面积矩形的坐标
    65. box = np.int0(box) # 将坐标规范化为整数
    66. angle = rect[2] #获取矩形相对于水平面的角度
    67. if angle > 0:
    68. if abs(angle) > 45:
    69. angle = 90 - abs(angle)
    70. else:
    71. if abs(angle) > 45:
    72. angle = (90 - abs(angle))
    73. # 绘制矩形
    74. # cv2.drawContours(img, [box], 0, (255, 0, 255), 3)
    75. print("轮廓数量", len(contours))
    76. return img, box, angle
    77. def rotate(img, angle):
    78. #旋转图片
    79. (h, w) = img.shape[:2] #获得图片高,宽
    80. center = (w // 2, h // 2) #获得图片中心点
    81. img_ratete = cv2.getRotationMatrix2D(center, angle, 1)
    82. rotated = cv2.warpAffine(img, img_ratete, (w, h))
    83. return rotated
    84. def cut1(img, box):
    85. #从轮廓出裁剪图片
    86. x1, y1 = box[1] #获取左上角坐标
    87. x2, y2 = box[3] #获取右下角坐标
    88. img_cut = img[y1+10:y2-10, x1+10:x2-10] #切片裁剪图像
    89. return img_cut
    90. def cut2(img, out_path, filed):
    91. #裁剪方格中图像并保存
    92. #@config i_:i为裁剪图像的y坐标区域, j_:j为裁剪图像的x坐标区域
    93. if not os.path.isdir(out_path): #创建文件夹
    94. os.makedirs(out_path)
    95. h, w, _ = img.shape #获取图像通道
    96. print(h, w)
    97. s,i_ = 0,0
    98. #循环保存图像
    99. for i in range(h//12,h,h//12):
    100. j_ = 0
    101. for j in range(w//8,w,w//8):
    102. imgd = img[i_ + 5:i - 5, j_ + 5:j - 5]
    103. # img_list.append(img[i_+10:i-10,j_+10:j-10])
    104. out_pathd = out_path+filed[:-4]+"_"+str(s)+".jpg" #图像保存路径
    105. cv2.imwrite(out_pathd,imgd)
    106. print("保存文件",out_pathd)
    107. s += 1
    108. j_ = j
    109. i_ = i
    110. if __name__ == "__main__":
    111. path = "/home/crxm/C1/" #读取图像文件夹
    112. put_path = "/home/crxm/C2/" #保存图像文件夹
    113. for file in os.listdir(path): #遍历访问图像
    114. pathd = path + file + "/"
    115. out_path = put_path + file + "/"
    116. for filed in os.listdir(pathd):
    117. img_path = (pathd + filed)
    118. img = cv2.imread(img_path) #读取图像
    119. img_separate = separate_color_red(img) #提取红色框先
    120. mediu = cv2.medianBlur(img_separate,19) #中值滤波,过滤除最外层框线以外的线条
    121. img_lines = lines(mediu) #直线检测,补充矩形框线
    122. img_contours,box,angle = contour(img_lines) #轮廓检测,获取最外层矩形框的偏转角度
    123. print("角度",angle,"坐标",box)
    124. img_rotate = rotate(img_lines,angle) #旋转图像至水平方向
    125. img_contours,box, _ = contour(img_rotate) #获取水平矩形框的坐标
    126. img_original_rotate = rotate(img,angle) #旋转原图至水平方向
    127. img_original_cut = cut1(img_original_rotate,box) #通过图像坐标从外层矩形框处裁剪原图
    128. cut2(img_original_cut,out_path,filed) #裁剪方格保存
    129. replace.replace(put_path) #消除多余红色框线
    130. # show("img",img)
    131. # show("img_separate", img_separate)
    132. # show("mediu", mediu)
    133. # show("img_lines", img_lines)
    134. # show("img_contours", img_contours)
    135. # show("img__rotate",img_rotate)
    136. # show("img_original_cut",img_original_cut)
    137. cv2.waitKey(0)
    138. cv2.destroyAllWindows()
    1. #replace.py
    2. from PIL import Image
    3. import os
    4. def replace(img_path):
    5. for path in os.listdir(img_path):
    6. path2 = img_path + path + "/"
    7. for pathd in os.listdir(path2):
    8. path3 = path2 + pathd
    9. img2 = Image.open(path3)
    10. img2 = img2.convert('RGBA') # 图像格式转为RGBA
    11. pixdata = img2.load()
    12. for y in range(img2.size[1]):
    13. for x in range(img2.size[0]):
    14. if pixdata[x, y][0] > 220: # 红色像素
    15. pixdata[x, y] = (255, 255, 255, 255) # 替换为白色,参数分别为(R,G,B,透明度)
    16. img2 = img2.convert('RGB') # 图像格式转为RGB
    17. print("替换文件",pathd)
    18. img2.save(path3)
    19. #红色像素替换为白色
    以太坊cppgolang区别 编程

    以太坊cppgolang区别

    以太坊是一种去中心化的开源平台,它采用智能合约技术,旨在构建和运行不受干扰的分布式应用程序。作为目前最受欢迎的区块链平台之一,以太坊提供了多种编程语言的支持,其
    progolang 编程

    progolang

    Go语言(Golang)是由Google开发的一门静态类型编程语言。作为一名专业的Golang开发者,我深知这门语言的优势和特点。在本文中,我将介绍Golang
    golangn个发送者 编程

    golangn个发送者

    Golang是一种开源的编程语言,由Google团队开发,旨在提高程序的并发性和简化软件开发过程。在Go语言中,有时需要向多个接收者发送信息。本文将介绍如何在G
    golang技能图谱 编程

    golang技能图谱

    从互联网行业的快速发展到人工智能技术的日益成熟,各种编程语言也应运而生。而在这众多的编程语言中,Golang(即Go)作为一门强大且高效的开发语言备受关注。Go
    评论:0   参与:  5