OpenCV – 指定插值方法改善resize函数缩放图片时出现锯齿、失真、清晰度降低问题
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
函数官方文档页面有以下的一句话
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
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
评论
52