尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

OpenCV双三次插值:原理、实战与避坑指南

OpenCV双三次插值:原理、实战与避坑指南 1. 从“像素搬家”到“像素再造”为什么我们需要双三次插值做图像处理的朋友对cv2.resize这个函数肯定不陌生。无论是为了适配不同分辨率的屏幕还是为深度学习模型准备统一尺寸的输入图像缩放都是最基础、最高频的操作之一。新手入门时往往只关心“怎么把图缩放到指定大小”随手就用上了默认的cv2.INTER_LINEAR双线性插值。这没错对于大多数日常应用双线性插值在速度和效果上取得了很好的平衡。但当你开始处理一些对图像质量有更高要求的场景时比如医学影像的细节放大、卫星图像的局部分析、或者艺术作品的超分辨率重建你就会发现双线性插值出来的图像边缘总有一种说不出的“糊”感像是蒙了一层薄纱。放大倍数越大这种模糊和锯齿感就越明显。这时候你就需要了解并尝试更高级的插值算法了而双三次插值BiCubic Interpolation正是从“够用”迈向“专业”的一道分水岭。简单来说图像缩放的本质是给新图像上的每个像素点“找颜色”。原始图像就像一张由已知颜色点像素构成的网格缩放后新图像的网格点像素位置变了很多点落在了原始网格的“空白”处。插值就是根据周围已知点的颜色来“猜”出这些新点的颜色。双线性插值只找最近的4个邻居上下左右来猜猜得比较粗糙而双三次插值则会考虑更远的16个邻居并且不是简单平均而是用一个更复杂的数学函数三次多项式去拟合像素值变化的曲面从而“猜”得更准、更平滑。我最初接触双三次插值是在一个古籍字画数字化修复的项目里。我们需要将扫描的局部高清图块无缝拼接到整体的低分辨率底图上。用双线性插值去放大底图时毛笔的飞白和印章的朱砂边缘会严重失真接缝处怎么处理都显得生硬。切换到双三次插值后虽然计算慢了一些但笔触的过渡和颜色的渐变自然了许多后期人工修饰的工作量直接减半。这个经历让我深刻体会到插值算法的选择不是一道简单的选择题而是对图像内容、应用场景和性能权衡的综合考量。今天我们就抛开那些复杂的数学公式从原理、实现到避坑彻底搞懂OpenCV中的双三次插值。2. 超越双线性双三次插值的核心思想与数学直觉要理解双三次插值为什么更好我们得先看看它到底在干什么。你可以把一张灰度图像想象成一个三维曲面x轴和y轴是像素坐标z轴是像素的灰度值如果是彩色图就是每个通道的强度值。图像缩放就是在这个已知的、离散的采样点像素曲面上去预测新坐标点的z值。2.1 邻居范围从4个点到16个点这是双三次与双线性最直观的区别。双线性插值对于目标点(x, y)它找到原始图像中最近的4个像素点通常是一个2x2的格子然后进行两次线性插值先x方向再y方向或者反过来。它只考虑了最直接的局部信息。双三次插值它的“视野”更广。对于目标点(x, y)它会找到其周围4x4共16个最近的像素点。这意味着它能感知到更远距离的像素变化趋势。为什么需要16个点因为双三次插值使用的拟合函数是双三次多项式。一个完整的三次多项式有10个系数。在二维情况下我们需要一个在x和y方向都是三次的函数其一般形式包含x³y³,x³y², ...,常数项等共16项。因此为了唯一确定这个多项式的所有系数我们至少需要16个已知条件即16个点的像素值。2.2 关键角色BiCubic核函数确定了用16个点下一个问题是怎么用不是简单平均而是给每个邻居像素分配一个权重距离目标点越近的像素权重通常越大。这个分配权重的函数就是BiCubic核函数Kernel Function。OpenCV等库中常用的BiCubic核函数是以下形式的分段三次函数对于距离 d (|x| 或 |y| 方向的距离)权重 w(d) 计算如下 w(d) { (a2)*|d|^3 - (a3)*|d|^2 1 for 0 |d| 1 a*|d|^3 - 5a*|d|^2 8a*|d| - 4a for 1 |d| 2 0 for |d| 2 }这里的a是一个可调参数通常取-0.5或-0.75。取a -0.5时它被称为“Mitchell-Netravali”滤波器的一种特例在平滑度和锐度之间有一个较好的平衡也是OpenCV默认采用的值。这个函数看起来复杂但我们可以直观理解|d|表示目标点与某个邻居像素在x或y方向上的归一化距离以像素为单位。例如目标点落在两个原始像素正中间那么到这两个像素在x方向的距离就是0.5。分段设计第一段(0 |d| 1)对应距离最近的4个像素在x或y方向上位于目标点两侧各一个像素以内。这部分函数曲线平滑保证近距离像素贡献大。第二段(1 |d| 2)对应次近的4个像素距离在1到2个像素之间。这部分函数产生了轻微的负权重当a为负时这是双三次插值的“魔法”所在。第三段(|d| 2)距离超过2个像素的邻居权重为0不参与计算。这解释了为什么只需要16个4x4邻居因为再远的像素距离都2权重为零。那个神奇的“负权重”是干什么的这是双三次插值比双线性“更清晰”的关键。负权重意味着某个邻居像素会对最终结果产生“反向拉扯”的作用。这听起来反直觉但它实际上起到了一个“反锐化”或“过冲”的效果。在图像边缘处这种机制可以部分补偿由插值带来的模糊使得重建的边缘看起来更陡峭、更锐利从而在视觉上保留了更多的细节。当然如果参数a设置不当比如负得太多这种过冲也可能导致边缘出现“振铃”伪影像水波纹一样的瑕疵。2.3 计算过程两次一维卷积了解了核函数整个双三次插值的计算过程就可以分解为两个步骤这大大简化了理解和实现水平方向插值对于目标点所在的水平行利用其左右各2个共4个像素的灰度值以及它们与目标点的水平距离dx通过BiCubic核函数计算权重进行一维插值得到该行在目标x坐标处的临时像素值。垂直方向插值将上一步得到的、位于同一垂直列上的4个临时像素值来自上下共4行利用它们与目标点的垂直距离dy再次通过BiCubic核函数计算权重进行第二次一维插值最终得到目标点(x, y)的像素值。这个过程在数学上等价于一个可分离的二维卷积操作先与一个水平方向的一维核卷积再与一个垂直方向的一维核卷积效率比直接进行二维卷积要高。注意这里描述的16个点是指最终影响结果的理论支持域。在实际编程中我们无需手动实现这个复杂的过程。OpenCV的cv2.resize(..., interpolationcv2.INTER_CUBIC)已经为我们高效、正确地封装了这一切。理解原理是为了更好地使用和调试它。3. OpenCV实战cv2.INTER_CUBIC 怎么用参数怎么调理论说得再多不如代码跑一遍。我们直接进入OpenCV的实操环节看看如何调用双三次插值并探索一些影响效果的关键参数。3.1 基础调用与效果对比首先准备一张有丰富细节的测试图比如一张带有文字、线条和渐变的图片。我们同时用双线性和双三次插值进行放大直观对比差异。import cv2 import numpy as np from matplotlib import pyplot as plt # 1. 读取图像 img cv2.imread(test_detail.jpg) # 替换为你的图片路径 if img is None: # 如果找不到图片创建一个简单的测试图 img np.zeros((100, 200, 3), dtypenp.uint8) cv2.putText(img, OpenCV, (30, 60), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2) cv2.line(img, (20, 80), (180, 80), (0, 255, 0), 1) print(使用生成的测试图) # 2. 定义缩放倍数 scale_factor 4.0 # 放大4倍 new_width int(img.shape[1] * scale_factor) new_height int(img.shape[0] * scale_factor) # 3. 应用不同的插值方法 img_linear cv2.resize(img, (new_width, new_height), interpolationcv2.INTER_LINEAR) img_cubic cv2.resize(img, (new_width, new_height), interpolationcv2.INTER_CUBIC) # 顺便对比最近邻插值感受差异 img_nearest cv2.resize(img, (new_width, new_height), interpolationcv2.INTER_NEAREST) # 4. 显示结果对比 plt.figure(figsize(15, 5)) plt.subplot(1, 4, 1) plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.title(Original) plt.axis(off) plt.subplot(1, 4, 2) plt.imshow(cv2.cvtColor(img_nearest, cv2.COLOR_BGR2RGB)) plt.title(INTER_NEAREST) plt.axis(off) plt.subplot(1, 4, 3) plt.imshow(cv2.cvtColor(img_linear, cv2.COLOR_BGR2RGB)) plt.title(INTER_LINEAR) plt.axis(off) plt.subplot(1, 4, 4) plt.imshow(cv2.cvtColor(img_cubic, cv2.COLOR_BGR2RGB)) plt.title(INTER_CUBIC) plt.axis(off) plt.tight_layout() plt.show() # 5. 裁剪局部区域进行细节观察例如观察文字边缘 crop_y, crop_x 50, 100 # 原始图中的大致位置 crop_h, crop_w 20, 80 # 注意放大后坐标需要乘以缩放倍数 crop_linear img_linear[crop_y*scale_factor:(crop_ycrop_h)*scale_factor, crop_x*scale_factor:(crop_xcrop_w)*scale_factor] crop_cubic img_cubic[crop_y*scale_factor:(crop_ycrop_h)*scale_factor, crop_x*scale_factor:(crop_xcrop_w)*scale_factor] plt.figure(figsize(10, 4)) plt.subplot(1, 2, 1) plt.imshow(cv2.cvtColor(crop_linear, cv2.COLOR_BGR2RGB)) plt.title(LINEAR (Detail)) plt.axis(off) plt.subplot(1, 2, 2) plt.imshow(cv2.cvtColor(crop_cubic, cv2.COLOR_BGR2RGB)) plt.title(CUBIC (Detail)) plt.axis(off) plt.tight_layout() plt.show()运行这段代码你应该能清晰地看到INTER_NEAREST锯齿感最重像马赛克但速度最快。INTER_LINEAR平滑了锯齿但整体感觉偏“软”边缘模糊。INTER_CUBIC在平滑的基础上边缘更清晰、更“硬朗”细节保留更好。仔细观察文字笔画和线条的边缘双三次插值的结果更接近我们对“清晰放大”的预期。3.2 隐藏的“坑”cv2.INTER_CUBIC 与 cv2.INTER_LANCZOS4OpenCV的插值标志里还有一个cv2.INTER_LANCZOS4。它使用Lanczos窗口的sinc函数作为核需要8x8的邻居区域64个点理论上能产生比双三次更锐利、伪影更少的结果但计算量也大得多。在很多人的测试和实际应用中尤其是在放大倍数不高2-4倍时INTER_CUBIC和INTER_LANCZOS4的视觉差异并不明显但后者耗时可能成倍增加。这里有一个非常重要的“坑”在OpenCV的某些版本尤其是较早版本中cv2.INTER_CUBIC的实现可能并不是标准的、带负系数的双三次卷积而是一种称为“双三次样条插值”的变体或者其参数a的取值不同。这可能导致其效果与理论或其他软件如Photoshop的“两次立方”有细微差别。OpenCV 4.x 以后版本的标准INTER_CUBIC实现已经比较稳定但如果你对插值质量有极致要求并且发现效果与预期不符可以尝试以下方法使用cv2.INTER_CUBIC的扩展形式OpenCV的resize函数还有一个不常用的参数fx和fy。一种更可控的方式是使用cv2.resize的dsizeNone并指定fx和fy缩放因子同时配合interpolation标志。但据我测试这与直接指定dsize在内部算法上无区别。手动实现或使用其他库验证对于关键应用可以用SciPy的ndimage.zoom函数提供order3的三次样条插值或PIL/Pillow库的Image.resize使用Image.BICUBIC进行交叉验证。不同库的底层实现和默认参数可能有差异。关注边界处理cv2.resize默认会进行边缘像素填充Padding以处理图像边界外的像素。当目标点靠近图像边缘时其所需的16个邻居可能有一部分在图像外。OpenCV默认会复制边缘像素cv2.BORDER_REPLICATE来填充这些区域。这在大多数情况下没问题但在极端放大边缘时可能引入轻微瑕疵。如果你需要更精确的控制可以考虑先将图像用某种方式如反射对称填充扩大再进行缩放最后裁剪。3.3 性能考量速度与质量的权衡双三次插值比双线性慢这是由其计算复杂性决定的。它需要为每个目标像素计算16个邻居的权重并加权平均计算量大约是双线性4个邻居的4倍。在实际项目中你需要权衡实时性要求高的场景如视频流实时缩放、游戏纹理映射优先使用INTER_LINEAR甚至INTER_NEAREST。可以考虑使用GPU加速的OpenCV版本或CUDA函数。对单张图片进行高质量离线处理如照片放大、预处理放心使用INTER_CUBIC或INTER_LANCZOS4。多花几毫秒到几百毫秒换来更好的质量是值得的。批量处理大量图片如果对质量要求不是极端苛刻INTER_LINEAR仍然是性价比最高的选择。如果必须用双三次可以考虑利用多线程或向量化操作来优化循环。一个简单的性能测试import time img cv2.imread(medium_image.jpg) # 一张中等大小的图片如 1024x768 target_size (img.shape[1]*2, img.shape[0]*2) # 放大两倍 start time.time() for _ in range(100): # 重复100次取平均 img_linear cv2.resize(img, target_size, interpolationcv2.INTER_LINEAR) linear_time (time.time() - start)/100 start time.time() for _ in range(100): img_cubic cv2.resize(img, target_size, interpolationcv2.INTER_CUBIC) cubic_time (time.time() - start)/100 print(fINTER_LINEAR average time: {linear_time*1000:.2f} ms) print(fINTER_CUBIC average time: {cubic_time*1000:.2f} ms) print(fCUBIC is about {cubic_time/linear_time:.1f} times slower than LINEAR.)在我的测试中双三次插值耗时通常是双线性的3到5倍具体倍数取决于图像大小、CPU性能以及OpenCV是否启用了优化如IPP、OpenCL。4. 不只是缩放双三次插值的变体与应用场景双三次插值的价值远不止于简单的resize函数。理解了它的原理你可以在很多更高级的图像处理任务中灵活运用或识别它。4.1 自定义核函数与参数a的调节如前所述BiCubic核函数中的参数a控制着平滑与锐化之间的平衡。OpenCV的默认实现使用了一个固定的a值通常是-0.75。但有些图像处理库或专业软件如Adobe Photoshop允许你微调这个参数。a -1这对应于B样条B-Spline插值。它非常平滑几乎不会产生振铃但也会让图像看起来更模糊。适合用于需要极度平滑、抑制噪声的插值场景。a -0.5这就是经典的Mitchell-Netravali滤波器。它在锐化和平滑之间取得了很好的平衡被广泛认为是通用性最好的设置。许多研究认为这是“视觉最优”的双三次插值参数。a 0这退化为双线性插值的某种立方形式不实际上当a0时第二段函数恒为0它变成了一个基于最近4个点的三次Hermite插值比双线性略好但不如负a值时锐利。a -0.75这是OpenCV和许多其他库的默认值。它比a-0.5稍锐利一些有时能产生更清晰的边缘但振铃风险也略高。如果你想在OpenCV之外实验不同的a值可以手动实现核函数或者使用SciPy的scipy.ndimage.map_coordinates配合自定义的样条阶数但SciPy用的是样条不是卷积核概念略有不同。4.2 图像旋转与仿射变换中的插值当你使用cv2.warpAffine或cv2.warpPerspective进行图像旋转、平移、仿射或透视变换时同样需要插值来计算输出图像中每个像素的值。interpolation参数在这里同样适用。import cv2 import numpy as np img cv2.imread(image.jpg) height, width img.shape[:2] # 定义一个旋转矩阵绕图像中心旋转30度 center (width // 2, height // 2) angle 30 scale 1.0 M cv2.getRotationMatrix2D(center, angle, scale) # 使用不同的插值方法进行旋转 img_rotated_linear cv2.warpAffine(img, M, (width, height), flagscv2.INTER_LINEAR) img_rotated_cubic cv2.warpAffine(img, M, (width, height), flagscv2.INTER_CUBIC) # 比较结果特别是旋转后斜边的锯齿和平滑度在几何变换中由于像素网格发生了非整形的映射插值质量对最终效果的影响更加明显。对于高质量的图像旋转尤其是大角度旋转使用INTER_CUBIC可以显著改善边缘的锯齿和模糊现象。4.3 超分辨率重建的基石现代基于深度学习的超分辨率Super-Resolution, SR技术已经取得了惊人成果。但你是否知道许多经典的、非深度学习的超分辨率算法其核心步骤之一就是基于双三次插值的例如在基于样例Example-Based的超分辨率方法中一个常见的流程是将低分辨率LR图像用双三次插值上采样到一个初始的高分辨率HR估计。这个估计是模糊的但提供了正确的尺寸和大致结构。然后利用一个预先训练好的字典或模型在这个模糊的HR估计基础上添加高频细节从而得到清晰的HR图像。在这里双三次插值作为初始化步骤其质量直接影响后续算法修复细节的难度。一个更平滑、振铃更少的初始估计可能通过调整参数a获得能为后续处理提供更好的起点。4.4 图像金字塔构建在构建高斯金字塔或拉普拉斯金字塔时通常需要对下层图像进行下采样缩小以生成上层图像。虽然下采样通常使用高斯模糊后简单隔点采样但在某些需要更高精度的多尺度分析中也可以考虑使用双三次插值先进行轻微的精调再进行采样。同样在从金字塔上层重建下层时上采样过程也可以使用双三次插值来获得更好的重建质量。5. 避坑指南双三次插值实际应用中的常见问题掌握了原理和调用方法在实际项目中应用双三次插值还会遇到一些坑。这里分享几个我踩过的以及如何绕过去。5.1 误区盲目认为“双三次一定最好”这是最常见的误区。双三次插值在放大上采样时通常优于双线性因为它能更好地重建高频信息边缘。但在缩小下采样时情况就不同了。缩小图像时信息量在减少多个像素合并成一个。这个过程的核心是抗锯齿Anti-aliasing即防止高频信息如细密纹理在下采样后产生莫尔条纹或混叠噪声。此时一个低通滤波器模糊是必要的。双线性插值本身具有一定的平滑作用。而双三次插值由于试图保留更多高频信息在缩小时有时反而可能保留或引入不需要的噪声和伪影。实践建议图像放大优先使用INTER_CUBIC或INTER_LANCZOS4。图像缩小对于普通缩小INTER_LINEAR通常是安全且效果不错的选择。如果缩小倍数非常大比如从4K缩到480p可以考虑先进行适当的高斯模糊再用INTER_LINEAR下采样或者直接使用INTER_AREA插值。INTER_AREA是什么这是OpenCV专门为图像缩小设计的一种插值方法。它使用像素区域关系进行重采样在缩小图像时能更好地保留对比度和整体结构同时有效抗锯齿。在需要高质量缩小的场景下INTER_AREA往往是首选。# 高质量图像缩小示例 img_large cv2.imread(large_image.jpg) small_size (640, 480) # 方法1使用 AREA (推荐用于缩小) img_small_area cv2.resize(img_large, small_size, interpolationcv2.INTER_AREA) # 方法2使用 LINEAR img_small_linear cv2.resize(img_large, small_size, interpolationcv2.INTER_LINEAR) # 对比两者AREA通常能更好地保持线条清晰度和避免混叠。5.2 彩色图像通道处理陷阱OpenCV默认以BGR顺序读取图像。当对彩色图像进行resize时插值是在每个通道上独立进行的。这听起来理所当然但有一个隐蔽问题颜色溢出Color Bleeding。在极端边缘比如一个纯红色物体255,0,0紧挨着纯蓝色背景0,0,255。在双三次插值计算时由于负系数的存在插值点可能会计算出负值或超过255的值。OpenCV的resize函数会负责将这些值钳制Clamp到 [0, 255] 范围内。但是这个钳制过程是各通道独立的。这可能导致在边缘处产生原本图像中不存在的颜色例如红色和蓝色插值出一些紫色或奇怪的灰度值。对于大多数自然图像这个问题不明显。但对于计算机生成的图形、图表、UI截图等包含大块纯色和尖锐边缘的图像这种颜色溢出可能会造成视觉上的瑕疵。解决方案转换色彩空间将图像从BGR转换到Lab或YUV色彩空间。在这些空间中亮度L或Y通道和颜色ab或UV通道是分离的。你可以对亮度通道使用INTER_CUBIC以保持边缘锐度而对颜色通道使用INTER_LINEAR甚至INTER_NEAREST因为人眼对颜色分辨的锐度不敏感。处理完后再转回BGR。使用专门的算法对于图形类图像的缩放有诸如“Super Sampling”或基于边缘指导的插值等更专业的算法但这些通常需要自己实现或寻找专门的库。5.3 与深度学习模型预处理的不匹配在深度学习项目中图像缩放是标准预处理步骤。TensorFlow、PyTorch等框架都有自己的图像加载和变换库如torchvision.transforms.Resize。这些库默认的插值方法可能不是双三次。例如早期版本的torchvision默认使用PIL.Image.BILINEAR。如果你在训练时用双线性而在部署时用OpenCV的双三次进行同样的预处理输入模型的图像就会有细微差异可能导致模型性能的轻微下降或波动。实践建议保持一致性在整个项目管线数据准备、训练、推理中强制使用同一种插值方法。最好在代码中显式指定而不是依赖默认值。了解框架默认值查阅你所用深度学习框架的文档明确其图像变换模块的默认插值方法。进行对齐测试编写一个简单的脚本用不同库PIL, OpenCV, torchvision和不同插值方法处理同一张图片保存结果并计算像素级差异如MSE, PSNR确保你的预处理流水线是确定和一致的。import torchvision.transforms as T from PIL import Image import numpy as np # 假设我们有一张PIL Image pil_img Image.open(test.jpg).convert(RGB) # Torchvision Resize, 明确指定插值 transform_cubic T.Resize((256, 256), interpolationT.InterpolationMode.BICUBIC) transform_linear T.Resize((256, 256), interpolationT.InterpolationMode.BILINEAR) tensor_cubic transform_cubic(pil_img) tensor_linear transform_linear(pil_img) # 转换为numpy数组与OpenCV结果对比 np_cubic_tv np.array(tensor_cubic) # PIL转numpy是RGB np_linear_tv np.array(tensor_linear) # OpenCV处理 (需要先转为BGR) img_cv cv2.imread(test.jpg) img_cv_cubic cv2.resize(img_cv, (256, 256), interpolationcv2.INTER_CUBIC) img_cv_linear cv2.resize(img_cv, (256, 256), interpolationcv2.INTER_LINEAR) # 注意颜色通道顺序OpenCV是BGR需要转换为RGB再比较 img_cv_cubic_rgb cv2.cvtColor(img_cv_cubic, cv2.COLOR_BGR2RGB) img_cv_linear_rgb cv2.cvtColor(img_cv_linear, cv2.COLOR_BGR2RGB) # 计算差异 diff_cubic np.abs(np_cubic_tv.astype(float) - img_cv_cubic_rgb.astype(float)).mean() diff_linear np.abs(np_linear_tv.astype(float) - img_cv_linear_rgb.astype(float)).mean() print(fBICUBIC difference between torchvision and OpenCV: {diff_cubic}) print(fBILINEAR difference between torchvision and OpenCV: {diff_linear}) # 理想情况下同一种方法的差异应该非常小1。如果差异大说明实现或默认参数有区别。5.4 性能瓶颈定位与优化当你发现图像处理流水线中resize是瓶颈时除了换用更快的插值方法还可以考虑以下优化减少不必要的缩放如果流水线中有多次缩放审视是否可以合并或消除某一步。降低缩放精度如果对质量要求不是极高可以尝试用INTER_LINEAR。或者对于非常大的图片可以考虑先缩放到一个中间尺寸再进行最终缩放。利用硬件加速OpenCV的UMat使用cv2.UMat将数据转移到OpenCL设备内存如果OpenCV编译时启用了OpenCL支持许多函数包括resize会自动在GPU上执行。img_umat cv2.UMat(img) # 上传到GPU如果可用 result_umat cv2.resize(img_umat, (new_w, new_h), interpolationcv2.INTER_CUBIC) result result_umat.get() # 下载回CPUCUDA如果你有NVIDIA GPU并且编译了OpenCV的CUDA模块可以使用cv2.cuda命名空间下的函数如cv2.cuda.resize性能提升会非常显著。批量处理如果有多张图片需要处理尽量使用向量化操作或循环优化避免单张处理带来的重复开销。双三次插值是一个强大的工具但它只是图像重采样工具箱中的一件。理解其原理、优势、局限以及与场景的匹配关系才能让你在项目中游刃有余。从“知其然”到“知其所以然”再到了解“何时用”和“怎么调”这个过程本身就是图像处理从业者功力增长的体现。下次当你再调用cv2.resize时不妨花一秒想想眼前的这张图真的需要双三次插值吗
返回列表