【深度学习】OpenCV 实战:从图片中精确提取扇子区域

发布时间:2026/6/29 18:46:32
【深度学习】OpenCV 实战:从图片中精确提取扇子区域 文章目录完整代码一览导入库与辅助函数定义显示图像函数cv_show辅助轮廓排序函数 sort_contours主程序流程读取图片缩放并逆时针旋转90度Canny 边缘检测查找轮廓筛选扇子外轮廓生成掩膜按位与操作提取扇子区域保存结果一个完整的图像提取流程读取图片 → 缩放 旋转 → Canny 边缘检测 → 查找轮廓 → 生成掩膜 → 按位与提取目标区域。项目要求一张名为fan.jpg的图片现要求使用 Python 结合 OpenCV 库编写代码实现以下功能1读取名为fan.jpg的图片将尺寸设置为宽640高480然后逆时针旋转90度2使用Canny边缘检测提取1处理后的边缘3在提取边缘的基础上查找轮廓并选取扇子的外轮廓生成相应的掩模4将步骤 1 处理后的图像与步骤 3 生成的掩模执行按位与操作提取扇子区域图像最终将结果保存为shanzi.png文件。样图fan.jpy完整代码一览import cv2 import numpy as np defcv_show(name,image):cv2.imshow(name,image)cv2.waitKey(0)defsort_contours(cnts,methodleft-to-right):reverseFalse i0ifmethodright-to-leftor methodbottom-to-top:reverseTrueifmethodtop-to-bottomor methodbottom-to-top:i1boundingBoxes[cv2.boundingRect(c)forc in cnts](cnts,boundingBoxes)zip(*sorted(zip(cnts,boundingBoxes),keylambda b:b[1][i],reversereverse))returncnts,boundingBoxes #----------主程序----------#(1)读取图片缩放并逆时针旋转90度 imgcv2.imread(r./fan.jpg)imgcv2.resize(img,(640,480))img_1np.rot90(img,k1)# k1表示逆时针旋转90度 cv2.imshow(yuan_tu,img)cv2.imshow(fan_image,img_1)cv2.waitKey(0)cv2.destroyAllWindows()#(2)Canny边缘检测 contours_imgimg_1.copy()graycv2.cvtColor(img_1,cv2.COLOR_BGR2GRAY)blurredcv2.GaussianBlur(gray,ksize(5,5),sigmaX0)cv_show(blurred,blurred)img_cannycv2.Canny(blurred,threshold175,threshold2200)cv_show(img_canny,img_canny)#(3)查找轮廓选取扇子的外轮廓生成掩膜 cntscv2.findContours(img_canny.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]cv2.drawContours(contours_img,cnts,-1,(0,0,255),3)cv_show(contours_img,contours_img)# 排序其实这里只有一个最大的轮廓但保留排序习惯 questionCnts[]forc in cnts:x,y,w,hcv2.boundingRect(c)questionCnts.append(c)questionCntssort_contours(questionCnts,methodtop-to-bottom)[0]fan_contsquestionCnts[0]# 取第一个最大的轮廓 masknp.zeros_like(gray)cv2.drawContours(mask,[fan_conts],-1,255,thickness-1)# thickness-1填充轮廓内部cv_show(img_mask,mask)#(4)按位与操作提取扇子区域 img_mask_andcv2.bitwise_and(img_1,img_1,maskmask)cv_show(img_mask_and,img_mask_and)# 保存结果 cv2.imwrite(shanzi.png,img_mask_and)导入库与辅助函数定义显示图像函数cv_showimport cv2 import numpy as np defcv_show(name,image):cv2.imshow(name,image)cv2.waitKey(0)辅助轮廓排序函数 sort_contoursdefsort_contours(cnts,methodleft-to-right):reverseFalse i0ifmethodright-to-leftor methodbottom-to-top:reverseTrueifmethodtop-to-bottomor methodbottom-to-top:i1boundingBoxes[cv2.boundingRect(c)forc in cnts](cnts,boundingBoxes)zip(*sorted(zip(cnts,boundingBoxes),keylambda b:b[1][i],reversereverse))returncnts,boundingBoxes主程序流程读取图片缩放并逆时针旋转90度imgcv2.imread(r./fan.jpg)imgcv2.resize(img,(640,480))img_1np.rot90(img,k1)cv2.imshow(yuan_tu,img)cv2.imshow(fan_image,img_1)cv2.waitKey(0)cv2.destroyAllWindows()运行结果Canny 边缘检测contours_imgimg_1.copy()graycv2.cvtColor(img_1,cv2.COLOR_BGR2GRAY)blurredcv2.GaussianBlur(gray,ksize(5,5),sigmaX0)cv_show(blurred,blurred)img_cannycv2.Canny(blurred,threshold175,threshold2200)cv_show(img_canny,img_canny)先复制旋转后的图像用于后面绘制轮廓再转为灰度图用 5×5 的核进行平滑去除噪点避免边缘检测时出现大量假边缘。Canny 边缘检测阈值 75 和 200 是经验值可根据图片对比度调整。数值越小检测出的边缘越丰富可能包含噪声越大则只保留最强边缘。运行结果查找轮廓筛选扇子外轮廓cntscv2.findContours(img_canny.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)[-2]cv2.drawContours(contours_img,cnts,-1,(0,0,255),3)cv_show(contours_img,contours_img)运行结果这里把所有轮廓放入列表然后用排序函数按从上到下排序——实际上因为只有一个大轮廓其他小噪声轮廓面积小排序后第一个就是面积最大的扇子轮廓。questionCnts[]forc in cnts:x,y,w,hcv2.boundingRect(c)questionCnts.append(c)questionCntssort_contours(questionCnts,methodtop-to-bottom)[0]fan_contsquestionCnts[0]生成掩膜masknp.zeros_like(gray)cv2.drawContours(mask,[fan_conts],-1,255,thickness-1)cv_show(img_mask,mask)运行结果按位与操作提取扇子区域对两张图像这里都是 img_1按位与但通过 mask 参数指定只有白色区域才参与运算黑色区域结果直接为 0。这样原图中只有扇子部分被保留背景全黑完美抠出扇子。img_mask_andcv2.bitwise_and(img_1,img_1,maskmask)cv_show(img_mask_and,img_mask_and)运行结果保存结果cv2.imwrite(shanzi.png,img_mask_and)