OpenCV入门学习(四):图像金字塔与图像透视转换

发布时间:2026/8/31 23:39:04
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风格迁移