OpenCV入门学习(四):图像金字塔与图像透视转换
OpenCV入门学习四图像金字塔与图像透视转换前言本文是OpenCV系列教程的第四篇。在掌握了图像预处理和轮廓检测之后我们将进入图像金字塔与图像透视转换的学习。图像金字塔用于图像的缩放与多尺度表示直方图操作用于分析图像灰度分布几何变换则用于图像的旋转与透视校正。本章涵盖四个核心知识点图像金字塔向下采样、向上采样、拉普拉斯金字塔、直方图与直方图均衡化、图像旋转、图像透视转换。目录一、图像金字塔二、直方图三、直方图均衡化四、图像旋转五、图像透视转换六、总结一、图像金字塔图像金字塔是图像多尺度表示的方法包括高斯金字塔和拉普拉斯金字塔。高斯金字塔通过向下采样缩小和向上采样放大构建拉普拉斯金字塔用于图像的细节恢复。1.1 向下采样pyrDown向下采样是一种减小图像尺寸的方法通过降低图像的分辨率来减少像素数量使图像看起来更小。核心函数dst cv2.pyrDown(src[, dst, dstsize[, borderType]])参数说明src原始图像dst目标图像dstsize目标图像的大小importcv2 slcv2.imread(sl.png)cv2.imshow(sl,sl)# 向下采样尺寸变为原来的1/4宽高各减半sl_down_1cv2.pyrDown(sl)cv2.imshow(sl_down_1,sl_down_1)# 再次向下采样sl_down_2cv2.pyrDown(sl_down_1)cv2.imshow(sl_down_2,sl_down_2)cv2.waitKey(0)cv2.destroyAllWindows()1.2 向上采样pyrUp向上采样是一种增大图像尺寸的方法通过插值和滤波技术恢复图像的分辨率。核心函数dst cv2.pyrUp(src[, dst, dstsize[, borderType]])# 向上采样尺寸变为原来的4倍宽高各扩大一倍sl_up_1cv2.pyrUp(sl)cv2.imshow(sl_up_1,sl_up_1)sl_up_2cv2.pyrUp(sl_up_1)cv2.imshow(sl_up_2,sl_up_2)cv2.waitKey(0)cv2.destroyAllWindows()1.3 向下采样后再向上采样信息丢失对向下采样后的图像进行向上采样图像会变模糊无法复原到原始清晰度。# 下采样后再上采样图像变模糊sl_down_1_upcv2.pyrUp(sl_down_1)sl_down_2_upcv2.pyrUp(sl_down_2)cv2.imshow(sl,sl)cv2.imshow(sl_down_1_up,sl_down_1_up)cv2.imshow(sl_down_2_up,sl_down_2_up)cv2.waitKey(0)cv2.destroyAllWindows()1.4 拉普拉斯金字塔拉普拉斯金字塔用于记录图像在向下采样过程中丢失的细节信息可用于图像复原。L0 原图 - 下采样后上采样复原图# 拉普拉斯金字塔L0sl-sl_down_1_up# 原始图像与复原图像的差值L1sl_down_1-sl_down_2_up# 图像复原上采样图 拉普拉斯差值fuyuansl_down_1_upL0 cv2.imshow(L0,L0)cv2.imshow(L1,L1)cv2.imshow(fuyuan,fuyuan)cv2.waitKey(0)cv2.destroyAllWindows()二、直方图直方图用于表示图像中像素灰度级别的分布情况。2.1 使用matplotlib绘制直方图importcv2importnumpyasnpfrommatplotlibimportpyplotasplt slcv2.imread(sl.png,cv2.IMREAD_GRAYSCALE)# 将图像转换为一维数组asl.ravel()# 绘制直方图plt.hist(a,bins256)# 参数解释:# a: 一维数组即图像的像素值组成的数组# bins256: 指定直方图的条数即灰度级的数量plt.show()2.2 使用calcHist计算直方图核心函数cv2.calcHist(images, channels, mask, histSize, ranges)参数说明images原图像用中括号括起来如[img]channels通道数。灰度图为[0]彩色图为[0][1][2]对应BGRmask掩模图像。统计整幅图设为None统计局部则传入掩模histSizeBINS的数目用中括号括起来ranges像素值范围通常为[0, 256]什么是BINS直方图显示了每个像素值(0~255)的像素数需要256个值。但可以将像素值分成区间统计如0~15、16~31…240~255只需16个值每个区间称为一个BIN。# 使用calcHist计算直方图BINS16sl_histcv2.calcHist([sl],[0],None,[16],[0,256])plt.plot(sl_hist)plt.show()2.3 掩模mask的使用掩模用于统计图像某一部分的直方图。imgcv2.imread(sl.png,cv2.IMREAD_GRAYSCALE)# 创建掩模指定区域设为255白色masknp.zeros(img.shape[:2],np.uint8)mask[50:650,100:600]255# 根据实际图像尺寸调整掩模区域cv2.imshow(mask,mask)# 对图像与掩模进行按位与操作提取指定区域# cv2.bitwise_and(): 对像素值进行二进制与操作111, 100, 010, 000sl_maskcv2.bitwise_and(img,img,maskmask)cv2.imshow(sl_mask,sl_mask)# 计算掩模区域的直方图phone_hist_maskcv2.calcHist([sl],[0],mask,[256],[0,256])plt.plot(phone_hist_mask)plt.show()cv2.waitKey(0)cv2.destroyAllWindows()三、直方图均衡化直方图均衡化是一种图像增强技术通过将图像的像素值分布均匀化来增强对比度和亮度。核心函数cv2.equalizeHist(src)importcv2importnumpyasnpfrommatplotlibimportpyplotasplt blackcv2.imread(black.jpg,cv2.IMREAD_GRAYSCALE)# 原图直方图plt.figure()plt.hist(black.ravel(),bins256)plt.show()# 直方图均衡化black_equalizecv2.equalizeHist(black)# 均衡化后直方图plt.figure()plt.hist(black_equalize.ravel(),bins256)plt.show()# 横向拼接原图与均衡化结果对比resnp.hstack((black,black_equalize))cv2.imshow(res,res)cv2.waitKey(0)cv2.destroyAllWindows()四、图像旋转4.1 方法一使用numpy.rot90()旋转90度的倍数核心函数np.rot90(img, k)参数说明img输入图像k旋转次数k-1顺时针旋转90°k1逆时针旋转90°importcv2importnumpyasnp imgcv2.imread(sl_yu.png)imgcv2.resize(img,None,fx2,fy2,interpolationcv2.INTER_AREA)# 旋转90度k-1表示顺时针旋转90度rotated_image1np.rot90(img,k-1)# 旋转90度k1表示逆时针旋转90度rotated_image2np.rot90(img,k1)cv2.imshow(yuantu,img)cv2.imshow(rotated_image1,rotated_image1)cv2.imshow(rotated_image2,rotated_image2)cv2.waitKey(0)cv2.destroyAllWindows()4.2 方法二使用cv2.rotate()旋转90度的倍数核心函数cv2.rotate(img, rotateCode)参数说明img输入图像rotateCode旋转代码rotateCode取值代码说明cv2.ROTATE_90_CLOCKWISE顺时针旋转90°cv2.ROTATE_90_COUNTERCLOCKWISE逆时针旋转90°cv2.ROTATE_180旋转180°rotated_imagecv2.rotate(img,cv2.ROTATE_90_CLOCKWISE)rotated_image1cv2.rotate(img,cv2.ROTATE_90_COUNTERCLOCKWISE)rotated_image2cv2.rotate(img,cv2.ROTATE_180)cv2.imshow(shun90,rotated_image)cv2.imshow(ni90,rotated_image1)cv2.imshow(180,rotated_image2)cv2.waitKey(0)cv2.destroyAllWindows()五、图像透视转换透视转换用于将图像从一个视角投影到另一个视角常用于文档扫描校正。5.1 辅助函数importcv2importnumpyasnpdefcv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)deforder_points(pts):对四个坐标点进行排序左上、右上、右下、左下rectnp.zeros((4,2),dtypefloat32)spts.sum(axis1)rect[0]pts[np.argmin(s)]# 左上坐标和最小rect[2]pts[np.argmax(s)]# 右下坐标和最大diffnp.diff(pts,axis1)rect[1]pts[np.argmin(diff)]# 右上y-x最小rect[3]pts[np.argmax(diff)]# 左下y-x最大returnrectdeffour_point_transform(image,pts):对图像进行透视变换rectorder_points(pts)(tl,tr,br,bl)rect# 计算目标图像的宽和高widthAnp.sqrt(((br[0]-bl[0])**2)((br[1]-bl[1])**2))widthBnp.sqrt(((tr[0]-tl[0])**2)((tr[1]-tl[1])**2))maxWidthmax(int(widthA),int(widthB))heightAnp.sqrt(((tr[0]-br[0])**2)((tr[1]-br[1])**2))heightBnp.sqrt(((tl[0]-bl[0])**2)((tl[1]-bl[1])**2))maxHeightmax(int(heightA),int(heightB))# 目标坐标dstnp.array([[0,0],[maxWidth-1,0],[maxWidth-1,maxHeight-1],[0,maxHeight-1]],dtypefloat32)# 计算透视变换矩阵并应用Mcv2.getPerspectiveTransform(rect,dst)warpedcv2.warpPerspective(image,M,(maxWidth,maxHeight))returnwarpeddefresize(image,widthNone,heightNone,intercv2.INTER_AREA):按指定宽度或高度缩放图像(h,w)image.shape[:2]ifwidthisNoneandheightisNone:returnimageifheightisnotNone:rheight/float(h)dim(int(w*r),height)else:rwidth/float(w)dim(width,int(h*r))resizedcv2.resize(image,dim,interpolationinter)returnresized5.2 发票扫描示例# 读取图像imagecv2.imread(fapiao.jpg)cv_show(image,image)# 图像过大先缩小处理ratioimage.shape[0]/500.0origimage.copy()imageresize(orig,height500)cv_show(resize,image)# 轮廓检测print(STEP 1: 轮廓检测)graycv2.cvtColor(image,cv2.COLOR_BGR2GRAY)edgedcv2.threshold(gray,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]cntscv2.findContours(edged.copy(),cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)[-2]image_contourscv2.drawContours(image.copy(),cnts,-1,(0,0,255),1)cv_show(image_contours,image_contours)# 获取最大轮廓发票主体print(STEP 2: 获取最大轮廓)screenCntsorted(cnts,keycv2.contourArea,reverseTrue)[0]pericv2.arcLength(screenCnt,True)screenCntcv2.approxPolyDP(screenCnt,0.05*peri,True)image_contourscv2.drawContours(image.copy(),[screenCnt],-1,(0,0,255),2)cv_show(image_contours,image_contours)# 透视变换warpedfour_point_transform(orig,screenCnt.reshape(4,2)*ratio)cv2.imwrite(invoice_new.jpg,warped)cv2.namedWindow(xx,cv2.WINDOW_NORMAL)cv2.imshow(xx,warped)cv2.waitKey(0)# 二值化后处理warpedcv2.cvtColor(warped,cv2.COLOR_BGR2GRAY)refcv2.threshold(warped,0,255,cv2.THRESH_BINARY|cv2.THRESH_OTSU)[1]cv_show(ref,ref)refresize(ref,width900)kernelnp.ones((2,2),np.uint8)ref_newcv2.erode(ref,kernel,iterations1)# 腐蚀去除噪点# 旋转校正rotated_imagecv2.rotate(ref_new,cv2.ROTATE_90_COUNTERCLOCKWISE)cv2.imshow(result,rotated_image)cv2.waitKey(0)cv2.destroyAllWindows()原图尺寸有点大仅粘贴部分示例六、总结核心函数速查类别函数用途向下采样pyrDown()图像缩小宽高减半向上采样pyrUp()图像放大宽高加倍计算直方图calcHist()计算图像灰度分布绘制直方图plt.hist()绘制直方图直方图均衡化equalizeHist()增强对比度numpy旋转np.rot90()旋转90度的倍数cv2旋转cv2.rotate()旋转90度的倍数透视变换矩阵getPerspectiveTransform()计算透视变换矩阵透视变换warpPerspective()应用透视变换系列直达上篇OpenCV入门学习三轮廓检测与模板匹配本篇OpenCV入门学习四图像金字塔与图像透视转换本文下篇OpenCV入门五图像拼接、背景建模、光流估计与DNN风格迁移

相关新闻

企业语音知识库怎么建设?从离线转写到可引用语音检索的完整路径

企业语音知识库怎么建设?从离线转写到可引用语音检索的完整路径

技术专题 / 企业级 AI 基础设施 录音变成知识,不是把文本丢进向量库:ASR、分段、权限、索引和证据回放必须一起设计 核心检索词:企业语音知识库、离线转写、语音检索、会议录音转文字、离线语音识别、ASR 知识库、企业 AI 搜索、语音识别私…

2026/10/26 10:17:14 阅读更多 →
Zuken Design Suite集成DFT插件:PCB可测试性设计实战解析

Zuken Design Suite集成DFT插件:PCB可测试性设计实战解析

我去年在试产评审会上看到过这样一幕:ICT首件测试覆盖率只有68%,板子上有十几个网络根本没法扎针,不是间距不够就是被元件挡住了。生产部门当着一屋子人的面说,这块板子要改版,设计同事一脸委屈——原理图没错&#xf…

2026/10/26 10:17:17 阅读更多 →
开关稳压器DC/DC转换器选型与设计实战:从原理到调试

开关稳压器DC/DC转换器选型与设计实战:从原理到调试

做硬件设计这几年,电源方案几乎是每个项目都绕不开的坎。尤其是给MCU、FPGA、传感器这些负载供电时,线性稳压器经常因为压差大、发热高被否掉,最后都得回到开关稳压器这条路上。最近看到村田(Murata)又扩展了他们的开关…

2026/10/26 10:17:22 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/10/27 17:33:32 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/10/28 7:28:00 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/10/28 9:02:11 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/10/27 18:20:50 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/10/28 9:00:54 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/10/28 7:29:02 阅读更多 →

日新闻

周新闻

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/28 16:58:40 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/28 9:01:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/27 19:19:37 阅读更多 →