OpenCV2:等间隔采样和局部均值的图像缩小
图像的缩小从物理意义上来说,就是将图像的每个像素的大小缩小相应的倍数。但是,改变像素的物理尺寸显然不是那么容易的,从数字图像处理的角度来看,图像的缩小实际就是通过减少像素个数来实现的。显而易见的,减少图像的像素会造成图像信息丢失。为了在缩小图像的同时,保持原图的概貌特征不丢失,从原图中选择的像素方法是非常重要的。本文主要介绍基于等间隔采样的图像缩小和基于局部均值的图像缩小以及其在OpenCV2的实现。
基于等间隔采样的图像缩小
这种图像缩小算法,通过对原图像像素进行均匀采样来保持所选择到的像素仍旧可以反映原图像的概貌特征。
算法描述
设原图的大小为W*H,宽度和长度的缩小因子分别为看k1和k2,那么采样间隔为:W/k1,W/k2.也就是说在原图的水平方向每隔W/k1,在垂直方向每隔W/k2取一个像素。长和宽的缩小因子k1和k2相等时,图像时等比例缩小,不等时是不等比例缩小,缩小图像的长和宽的比例会发生变化。
基于OpenCV的算法实现
void scaleIntervalSampling(const Mat &src, Mat &dst, double xRatio, double yRatio)
{
//只处理uchar型的像素
CV_Assert(src.depth() == CV_8U); // 计算缩小后图像的大小
//没有四舍五入,防止对原图像采样时越过图像边界
int rows = static_cast<int>(src.rows * xRatio);
int cols = static_cast<int>(src.cols * yRatio); dst.create(rows, cols, src.type()); const int channesl = src.channels(); switch (channesl)
{
case : //单通道图像
{
uchar *p;
const uchar *origal; for (int i = ; i < rows; i++){
p = dst.ptr<uchar>(i);
//四舍五入
//+1 和 -1 是因为Mat中的像素是从0开始计数的
int row = static_cast<int>((i + ) / xRatio + 0.5) - ;
origal = src.ptr<uchar>(row);
for (int j = ; j < cols; j++){
int col = static_cast<int>((j + ) / yRatio + 0.5) - ;
p[j] = origal[col]; //取得采样像素
}
}
break;
} case ://三通道图像
{
Vec3b *p;
const Vec3b *origal; for (int i = ; i < rows; i++) {
p = dst.ptr<Vec3b>(i);
int row = static_cast<int>((i + ) / xRatio + 0.5) - ;
origal = src.ptr<Vec3b>(row);
for (int j = ; j < cols; j++){
int col = static_cast<int>((j + ) / yRatio + 0.5) - ;
p[j] = origal[col]; //取得采样像素
}
}
break;
}
}
}
代码实现还是比较简单的,需要注意的一点就是对于单通道和三通道图像用ptr取行地址时,使用的数据类型的不同。三通道图像中,一个像素有BGR三个分量,可以使用Vec3b来保存。
运行结果

基于局部均值的图像缩小
算法描述
等间隔采样的缩小方法实现简单,但是原图像中未被选中的像素信息会在缩小后的图像中丢失。局部均值的图像缩小方法对其进行了改进。在求缩小图像的像素时,不仅仅单纯的取在原图像中的采样点像素,而是以相邻的两个采样点为分割,将原图像分成一个个的子块。缩小图像的像素取相应子块像素的均值。

根据局部均值缩小的原理:g11 = (f11 + f12 + f21 + f22 ) / 4
基于OpenCV的算法实现
void scalePartAverage(const Mat &src, Mat &dst, double xRatio, double yRatio)
{
int rows = static_cast<int>(src.rows * xRatio);
int cols = static_cast<int>(src.cols * yRatio); dst.create(rows, cols, src.type()); int lastRow = ;
int lastCol = ; Vec3b *p;
for (int i = ; i < rows; i++) {
p = dst.ptr<Vec3b>(i);
int row = static_cast<int>((i + ) / xRatio + 0.5) - ; for (int j = ; j < cols; j++) {
int col = static_cast<int>((j + ) / yRatio + 0.5) - ; Vec3b pix;
average(src, Point_<int>(lastRow, lastCol), Point_<int>(row, col), pix);
p[j] = pix; lastCol = col + ; //下一个子块左上角的列坐标,行坐标不变
}
lastCol = ; //子块的左上角列坐标,从0开始
lastRow = row + ; //子块的左上角行坐标
}
}
算法实现只考虑了三通道图像,单通道图像与之类似。
局部均值缩小图片实现的关键点在子块左上角行和列坐标的求取(子块右下角行和列坐标,就是间隔采样的采样点)。图像子块求出后,计算出子块像素的平均值即是缩小图像的像素。
子块平均像素的求解
void average(const Mat &img, Point_<int> a, Point_<int> b, Vec3b &p)
{ const Vec3b *pix;
Vec3i temp;
for (int i = a.x; i <= b.x; i++){
pix = img.ptr<Vec3b>(i);
for (int j = a.y; j <= b.y; j++){
temp[] += pix[j][];
temp[] += pix[j][];
temp[] += pix[j][];
}
} int count = (b.x - a.x + ) * (b.y - a.y + );
p[] = temp[] / count;
p[] = temp[] / count;
p[] = temp[] / count;
}
求取局部平均值时,要注意数据类型。Vec3b实际就元素类型为uchar的Vector,也就是说Vec3b的每一个分量的最大值是255.而求均值时,需要累加像素值,使用uchar时会越界,为此,这里使用Vec3i作为中间值保存。Vec3i是int型的Vector。
运行结果

两种方法的比较


上面两幅图像都是512 * 512的lenna图片缩小到0.3,左边为使用局部均值的算法,右边是使用等间隔采样的算法。
下一章准备介绍下OpenCV下实现几种常见的图像放大方法。
OpenCV2:等间隔采样和局部均值的图像缩小的更多相关文章
- NLM非局部均值算法相关
NLM原文: 基于图像分割的非局部均值去噪算法 基于图像分割的非局部均值去噪算法_百度文库 https://wenku.baidu.com/view/6a51abdfcd22bcd126fff705c ...
- 非局部均值(Nonlocal-Mean)
转载自网站:http://www.cnblogs.com/luo-peng/p/4785922.html 非局部均值去噪(NL-means) 非局部均值(NL-means)是近年来提出的一项新型的 ...
- 非局部均值去噪(NL-means)
非局部均值(NL-means)是近年来提出的一项新型的去噪技术.该方法充分利用了图像中的冗余信息,在去噪的同时能最大程度地保持图像的细节特征.基本思想是:当前像素的估计值由图像中与它具有相似邻域结构的 ...
- 积分图像的应用(二):非局部均值去噪(NL-means)
非局部均值去噪(NL-means)一文介绍了NL-means基本算法,同时指出了该算法效率低的问题,本文将使用积分图像技术对该算法进行加速. 假设图像共像个素点,搜索窗口大小,领域窗口大小, 计算两个 ...
- stm32_ADC定时器采样(DMA均值处理数据)
在有些要求高的场合,需要用到定时器采样.本人在网上没找到合适的源码,于是将自己的思路分享出来,欢迎大家提出意见. 确定ADC采用的通道对应的通道 确定采样对应的引脚(这个在规格书的引脚定义部分可以找到 ...
- 非局部均值滤波算法的python实现
如题,比opencv自带的实现效果好 #coding:utf8 import cv2 import numpy as np def psnr(A, B): return 10*np.log(255*2 ...
- OpenCV2+入门系列(四):计算图像的直方图,平均灰度,灰度方差
本篇懒得排版,直接在网页html编辑器编辑 在图像处理时,我们常常需要求出图像的直方图.灰度平均值.灰度的方差,这里给出一个opencv2+自带程序,实现这些功能. 直方图 对于直方图,使用cv::c ...
- OpenCV2+入门系列(三):遍历图像的几种方法
根据OpenCV中Mat类型的结构和内存中存储方式,此处给出三种对图像进行遍历的方法.首先给出基础的读取图片代码,在中间替换三种遍历方法即可,本文中,程序将遍历图像并将所有像素点置为255,所有运行结 ...
- OpenCV2类批量处理文件夹及文件图像 及批量处理后保存到txt文件
//采用windows控制台实现计算文件夹中对象总数以及批量读取对象 //#include <afx.h> //和windows.h是一样的作用 #include <opencv2/ ...
随机推荐
- IIS和4.0安装到底有没有先后顺序解答
在很多人或许很多技术大神都会觉得IIS的安装和4.0没得先后顺序的.其错误弊端在与IIS没有注册到4.0上. 经过今天遇到了服务器安装服务端发觉报错[无法识别的属性“targetFramework”. ...
- PHP基础知识之魔术方法
__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sle ...
- android输入限制
title: 2016-5-30 Android输入验证 tags: EditText,输入验证 --- 前言2 使用EditText让用户输入文字时,需要对输入验证.除过验证是否有效的逻辑不同,Ed ...
- 小知识 安卓线程和ui
*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...
- UI控件(UIToolbar)
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; _toolbar = [[UIToolbar all ...
- adb server is out of date. killing...
1.查看adb端口号 adb nodaemon server 打印:cannot bind 'tcp:5037' 2.查看端口被哪个进程占用 netstat -ano | findstr " ...
- HTML5中类jQuery选择器querySelector的使用
简介 HTML5向Web API新引入了document.querySelector以及document.querySelectorAll两个方法用来更方便地从DOM选取元素,功能类似于jQuery的 ...
- C语言 · 特殊回文数
问题描述 123321是一个非常特殊的数,它从左边读和从右边读是一样的. 输入一个正整数n, 编程求所有这样的五位和六位十进制数,满足各位数字之和等于n . 输入格式 输入一行,包含一个正整数n. 输 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (43) ------ 第八章 POCO之使用POCO加载实体
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 8-2 使用POCO加载关联实体 问题 你想使用POCO预先加载关联实体. 解决方 ...
- 使用easyui-layout布局
<body class="easyui-layout"> <div data-options="region:'north',title:'顶部',sp ...