![图像处理与计算机视觉实践:基于OpenCV和Python](https://wfqqreader-1252317822.image.myqcloud.com/cover/890/48162890/b_48162890.jpg)
2.1 缩放
缩放是最简单的仿射变换,顾名思义,应用它可将图像放大或缩小。图2-2所示是一幅原始图像,图2-3(a)所示是缩小后的图像,图2-3(b)所示是放大后的图像。
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/TX00249.jpg?sign=1739303593-T7DYqqZnN5yRzXMuSwfq6Gj2jAv9vlma-0-9459fd31344be3c8c6a4072baf0342f8)
图2-2 原始图像
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/TX00250.jpg?sign=1739303593-8lgqCzV8psoKxJWokpVKpHpxiicAYmwq-0-c9f22c4142345e139744392f137961e5)
(a)
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/TX00251.jpg?sign=1739303593-3ye5sMu0Mm10aH2LKHvJGlPFCNYBP8k4-0-f43183a38d64c667a42abb0e5a2e7341)
(b)
图2-3 图2-2缩放后的图像
将图像放大或缩小后会得到新图像,比如将100×100的图像放大为200×200,如果原始图像有1万个像素点,那么新图像中有4万个像素点,这4万个像素点的值应该怎么根据原始图像的像素值来计算呢?这就需要用到一个重要的技术——插值。
我们先来看一个例子。如图2-4所示,有一幅大小为3×3的图像,将其按长宽等比例放大4/3倍后得到一幅4×4的新图像,新图像中(2, 1)位置的像素对应于原始图像(1.5, 0.75)位置。但是原始图像的像素都位于整数坐标位置,于是新图像在原始图像中的对应点(1.5, 0.75)位置的像素值就需要根据其周围在整数位置的像素值来计算得出,比如可以用图2-4(a)中深色区域的4个像素来计算,这就是插值。
最简单的插值方法就是直接取距离(1.5, 0.75)最近的整数位置像素的值,这种方法叫作最近邻插值。
双线性插值是一种常用的插值方法,它是线性插值的扩展。在数学上,线性插值是一种曲线拟合的方法,它通过线性多项式来计算已知相邻数据点之间的点。如图2-5所示,假设已知和
两点,用线性插值可以计算出这两点间连线上的点,也就是说给出x0和x1间的一个值x,对应的y值可用下面的式(2-1)计算得出:
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/TX00254.jpg?sign=1739303593-MIlDRm1wRNkILXuKM7mI7CvHR9gpqw9c-0-a9852fb72e6b09d5c3f18f461784ba84)
即
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/TX00255.jpg?sign=1739303593-06tX5cZCGq31aIluO07RRfvEwyX4aF8H-0-e1909e90e1a231de7921786d42052ac7)
式(2-1)
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/TX00256.jpg?sign=1739303593-9HDCk8tEyRjFOc8DwUoo64i7rX3yqG8P-0-75c2f9bbb41caefe17e319e6c55138c2)
(a) (b)
图2-4 插值
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/TX00257.jpg?sign=1739303593-hC88NXMyckqPEXthwpK9qrLDwN25VOPO-0-6ce2ed94fe9ae01dd7c2ca0eb039f0c5)
图2-5 线性插值
对线性插值进行扩展,在两个方向上分别进行一次线性插值,即对x和y都进行插值,这样的方法就称为双线性插值。如图2-6所示,我们需要得到点的值,假设已知
、
、
和
这4个点的值。
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/TX00263.jpg?sign=1739303593-YzItYDaR8GKbp6r4IrqtNDpoweFe5jVw-0-45361a0a96045b5782b1619f233c2b7f)
图2-6 双线性插值
先在x轴方向进行线性插值,得到和
点的值:
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/TX00266.jpg?sign=1739303593-zvBylPgSfKRiFUUKo8YErIRl5IPu4ric-0-8da7714a2e27f04638d8d92ba2cb9300)
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/TX00267.jpg?sign=1739303593-tFl7JsKm81q1bOPXdzMObF7HJpm3DyzZ-0-21349ffe7ccc4626d847dc28c2e4aed8)
式(2-2)
然后在y轴方向根据点和
进行线性插值,便得到点P的值:
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/TX00270.jpg?sign=1739303593-gn3714zeVN3o4iryMtd4cWKSEJ2s28fi-0-4fab55fe4cd96c14e6072edff676ca3f)
式(2-3)
双线性插值的结果与插值顺序无关,先进行x轴方向插值和先进行y轴方向插值的最终结果是一样的。需要注意的是,双线性插值并不是线性的,而是非线性的。对于其他的插值方法,感兴趣的读者可以查阅相关资料进行了解。
OpenCV提供了对图像进行缩放的函数cv.resize(),该函数支持多种插值方法。
dst = cv.resize(src, dsize[, fx[, fy[, interpolation]]])
其中的主要参数介绍如下。
● dst:输出图像,大小为dsize,或由src的大小、fx和fy计算得到。
● src:输入图像。
● dsize:输出图像的大小。如果其为None,则
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/TX00271.jpg?sign=1739303593-4ZWOOLyr1L2SHjDttiDHO1BCfzw5EcbS-0-19893d5da2473e7bab643a344b60489b)
● fx:图像宽的缩放比例。如果该值为0,则按计算得出。
● fy:图像高的缩放比例。如果该值为0,则按计算得出。
● interpolation:插值方法。插值方法和说明如表2-1所示。默认的插值方法是双线性插值INTER_LINEAR。
表2-1 插值方法和说明
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/5.jpg?sign=1739303593-LUUcgQOElQ6dHsEZ14ygXwH5EDY3X1MR-0-3dc8892c174bff56686ce77b7c650fbc)
不同的插值方法会产生不同质量的图像,同时它们的计算速度也不一样。图2-7中的4幅图为采用不同的插值方法将图2-2放大2倍后的图像,图2-7(a)~图2-7(d)依次为使用最近邻插值、双线性插值、双三次插值和LANCZOS插值得到的新图像。对比结果可以看出,最近邻插值会让图像产生锯齿效果,双线性插值会让图像边缘变模糊,而双三次插值和LANCZOS插值的效果均较好。从速度上看,这4种插值方法中,最近邻插值速度最快,双线性插值的速度较快,双三次插值的速度一般,而LANCZOS插值的速度最慢。
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/TX00001.jpg?sign=1739303593-UqZuZf10hjEDnyxG6euudh6d1e7ZNIZX-0-9fd0a5d06dbabf5b00c5f89d86e8cfc3)
(a)
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/TX00002.jpg?sign=1739303593-9WI00tXMuPsiQze9y08t0yVzSU0rV0HS-0-c1a969d8126e7a57c2dbdfa6035081ae)
(b)
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/TX00003.jpg?sign=1739303593-FbbfzNGgcZ6kUhGmW4PSZBpsa9PUjIAm-0-ba6c5a26e586992d240b193061145a11)
(c)
![](https://epubservercos.yuewen.com/EA8E88/27665459102692206/epubprivate/OEBPS/Images/TX00004.jpg?sign=1739303593-qLZlPeZlUjW9cVHKyNq5ayLkOb9KnjCE-0-70bde2df9850104139dc2ff025e6dff1)
(d)
图2-7 使用不同的插值方法将图2-2放大2倍后的图像
实现代码如下:
import cv2 as cv import numpy as np def main(): # 读入图像 im = cv.imread('lena.jpg') cv.imshow('lena.jpg', im) # 缩放图像 dim = (int(im.shape[1]*2), int(im.shape[0]*2)) im_rs_nr = cv.resize(im, dim, interpolation=cv.INTER_NEAREST) im_rs_ln = cv.resize(im, dim, interpolation=cv.INTER_LINEAR) im_rs_cb = cv.resize(im, dim, interpolation=cv.INTER_CUBIC) im_rs_lz = cv.resize(im, dim, interpolation=cv.INTER_LANCZOS4) cv.imshow('lena_rs_nr.jpg', im_rs_nr) cv.imshow('lena_rs_ln.jpg', im_rs_ln) cv.imshow('lena_rs_cb.jpg', im_rs_cb) cv.imshow('lena_rs_lz.jpg', im_rs_lz) cv.waitKey() cv.destroyAllWindows() if __name__ == '__main__': main()