• 在本站开通年度VIP,无限制下载本站资源和阅读本站文章

  • 感谢大家访问本站,希望本站的内容可以帮助到大家!

  • 工资「喂饱肚子」,副业「养活灵魂」!

  • 欢迎大家交换友链,可在https://www.stubbornhuang.com/申请友情链接进行友链交换申请!

  • 本站会放置Google广告用于维持域名以及网站服务器费用。

  • 如果觉得本站的内容有帮助,可以考虑打赏博主哦!

  • 问题反馈可发送邮件到stubbornhuang@qq.com

  • 本站由于前段时间遭受到大量临时和国外邮箱注册,所以对可注册的邮箱类型进行了限制!

  • 计算机图形学与计算几何经典必备书单整理,下载链接可参考:https://www.stubbornhuang.com/1256/

OpenCV – 指定插值方法改善resize函数缩放图片时出现锯齿、失真、清晰度降低问题

OpenCV 发布于2022-11-10 阅读 6,349次 0次评论 0次点赞 本文共4629个字,阅读需要12分钟。

1 指定插值方法改善resize函数缩放图片时出现锯齿感和失真问题

最近使用OpenCV对视频数据进行裁剪和缩放到指定的分辨率时,发现如果只是裁剪视频两侧多余的背景,视频的清晰度还是和原视频一样保持不变,但是如果在裁剪之后继续缩放到指定的分辨率,最后的结果数据就会出现比较严重的锯齿感和失真,与原视频的清晰度差别很大。

1.1 从OpenCV中resize的官方文档中学习

在出现以上问题之后,我细细查看了resize函数的官方文档,文档链接:https://docs.opencv.org/4.x/da/d54/group__imgproc__transform.html#ga47a974309e9102f5f08231edc7e7529d

函数原型

C++的函数原型

void cv::resize (   InputArray  src,
    OutputArray     dst,
    Size    dsize,
    double  fx = 0,
    double  fy = 0,
    int     interpolation = INTER_LINEAR
)

Python的函数原型

    cv.resize(  src, dsize[, dst[, fx[, fy[, interpolation]]]]  ) ->    dst

函数参数

  • src:输入图片;
  • dst:输出图片;
  • dszie:输出图片的大小
  • fx:沿水平方向(宽度)的缩放因子,当fx=0时,即为(double)dsize.width/src.cols;
  • fy:沿垂直方向(高度)的缩放因子,当fy=0时,即为(double)dsize.height/src.rows;
  • interpolation:插值方法,默认的方法为INTER_LINEAR(双线性插值)

其中插值方法为resize函数在缩放图片时使用的插值方式,其中可选的插值方法可参考官方文档https://docs.opencv.org/4.x/da/d54/group__imgproc__transform.html#gga5bb5a1fea74ea38e1a5445ca803ff121acf959dca2480cc694ca016b81b442ceb

这里我们简单的例举以下可用的插值方法:

插值方法 说明
INTER_NEAREST Python: cv.INTER_NEAREST 最近邻插值
INTER_LINEAR Python: cv.INTER_LINEAR 双线性插值
INTER_CUBIC Python: cv.INTER_CUBIC 双三次插值
INTER_AREA Python: cv.INTER_AREA 使用像素面积关系重新采样。这可能是图像抽取的首选方法,因为它可以提供无云纹的结果。但当图像被缩放时,它类似于INTER_NEAREST方法。
INTER_LANCZOS4 Python: cv.INTER_LANCZOS4 8x8邻域上的Lanczos插值
INTER_LINEAR_EXACT Python: cv.INTER_LINEAR_EXACT 位精确双线性插值
INTER_NEAREST_EXACT Python: cv.INTER_NEAREST_EXACT 位精确最近邻插值。这将产生与PIL、scikit图像或Matlab中的最近邻方法相同的结果。

resize函数官方文档页面有以下的一句话

OpenCV - 指定插值方法改善resize函数缩放图片时出现锯齿、失真、清晰度降低问题-第0张图片

To shrink an image, it will generally look best with INTER_AREA interpolation, whereas to enlarge an image, it will generally look best with INTER_CUBIC (slow) or INTER_LINEAR (faster but still looks OK).

意思是如果我们要缩小图像,使用INTER_AREA插值方法的效果是最好的,而如果放大图片,INTER_CUBIC的效果是最好的但是速度慢,而INTER_LINEAR方法速度快然后效果看起来也可以。

1.2 合理使用resize时的插值方法

从上述官方文档中学到,由于之前在使用resize时没有显式指定插值方法,而是一直使用的默认插值方法INTER_LINEAR,所以不管是缩小还是放大图片效果都不是很好,而为了比较每一种插值方法,我写了一个Python脚本验证每一个插值方法的效果

# -*- coding: utf-8 -*-

import os
import sys
import cv2
import re

def center_crop_video_according_to_width(input_video_path,out_video_path,interpolation,video_out_size='256x256px'):
    # 判断视频文件是否存在
    if not os.path.exists(input_video_path):
        print('输入的视频文件不存在')
        sys.exit(0)

    # 如果输出文件夹不存在则创建
    output_base_path = os.path.dirname(out_video_path)
    if not os.path.exists(output_base_path):
        try:
            os.makedirs(output_base_path)
        except FileExistsError:
            print('所需创建的文件夹已存在')

    if os.path.exists(out_video_path):
        print('裁剪视频输出文件存在,将删除原有路径视频')
        os.remove(out_video_path)

    # 获取原有视频参数
    video_read_capture = cv2.VideoCapture(input_video_path)
    input_video_width = int(video_read_capture.get(cv2.CAP_PROP_FRAME_WIDTH))
    input_video_height = int(video_read_capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
    input_video_fps = int(video_read_capture.get(cv2.CAP_PROP_FPS))
    input_video_fourcc = int(video_read_capture.get(cv2.CAP_PROP_FOURCC))

    # 创建写视频对象
    out_size = tuple(int(res) for res in re.findall("\d+", video_out_size))
    output_video_fourcc = int(cv2.VideoWriter_fourcc(*'mp4v'))
    video_write_capture = cv2.VideoWriter(out_video_path,output_video_fourcc,input_video_fps,out_size)

    while video_read_capture.isOpened():
        result, frame = video_read_capture.read()
        if not result:
            break

        # 裁剪到与原视频高度等宽的视频
        diff = input_video_width - input_video_height
        diff = int(diff / 2)
        crop_start_index = int(diff)
        crop_end_index = int(diff + input_video_height)

        # 参数1 是高度的范围,参数2是宽度的范围
        target = frame[0:int(input_video_height), crop_start_index:crop_end_index]

        # 再resize到目标大小
        target = cv2.resize(target, out_size, interpolation=interpolation)

        # 写输出视频帧
        video_write_capture.write(target)

    video_read_capture.release()
    video_write_capture.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    center_crop_video_according_to_width(r"C:\Users\Administrator\Desktop\video_input\a.mp4",
                                         r"C:\Users\Administrator\Desktop\video_output\a_INTER_NEAREST.mp4",
                                         cv2.INTER_NEAREST)

    center_crop_video_according_to_width(r"C:\Users\Administrator\Desktop\video_input\a.mp4",
                                         r"C:\Users\Administrator\Desktop\video_output\a_INTER_LINEAR.mp4",
                                         cv2.INTER_LINEAR)

    center_crop_video_according_to_width(r"C:\Users\Administrator\Desktop\video_input\a.mp4",
                                         r"C:\Users\Administrator\Desktop\video_output\a_INTER_CUBIC.mp4",
                                         cv2.INTER_CUBIC)

    center_crop_video_according_to_width(r"C:\Users\Administrator\Desktop\video_input\a.mp4",
                                         r"C:\Users\Administrator\Desktop\video_output\a_INTER_AREA.mp4",
                                         cv2.INTER_AREA)

    center_crop_video_according_to_width(r"C:\Users\Administrator\Desktop\video_input\a.mp4",
                                         r"C:\Users\Administrator\Desktop\video_output\a_INTER_LANCZOS4.mp4",
                                         cv2.INTER_LANCZOS4)

    center_crop_video_according_to_width(r"C:\Users\Administrator\Desktop\video_input\a.mp4",
                                         r"C:\Users\Administrator\Desktop\video_output\a_INTER_LINEAR_EXACT.mp4",
                                         cv2.INTER_LINEAR_EXACT)

    center_crop_video_according_to_width(r"C:\Users\Administrator\Desktop\video_input\a.mp4",
                                         r"C:\Users\Administrator\Desktop\video_output\a_INTER_NEAREST_EXACT.mp4",
                                         cv2.INTER_NEAREST_EXACT)

经过比较,在缩小视频时使用INTER_AREA的插值方法生成的图片质量确实是最好的。

欢迎扫码关注我的微信公众号,及时获取文章更新

微信公众号二维码

本文作者:StubbornHuang

版权声明:本文为站长原创文章,如果转载请注明原文链接!

原文标题:OpenCV – 指定插值方法改善resize函数缩放图片时出现锯齿、失真、清晰度降低问题

原文链接:https://www.stubbornhuang.com/2410/

发布于:2022年11月10日 14:07:09

修改于:2023年06月21日 17:52:42

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

文章末尾
上一篇
C++ - return this和return *this的含义和区别
C++
下一篇
C++ - 拷贝构造函数与拷贝构造函数调用时机
C++
当前分类随机文章推荐

发表评论

您必须 [ 登录 ] 才能发表留言!

关注我们的公众号

微信公众号