图像的缩小从物理意义上来说,就是将图像的每个像素的大小缩小相应的倍数。但是,改变像素的物理尺寸显然不是那么容易的,从数字图像处理的角度来看,图像的缩小实际就是通过减少像素个数来实现的。显而易见的,减少图像的像素会造成图像信息丢失。为了在缩小图像的同时,保持原图的概貌特征不丢失,从原图中选择的像素方法是非常重要的。本文主要介绍基于等间隔采样的图像缩小和基于局部均值的图像缩小以及其在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:等间隔采样和局部均值的图像缩小的更多相关文章

  1. NLM非局部均值算法相关

    NLM原文: 基于图像分割的非局部均值去噪算法 基于图像分割的非局部均值去噪算法_百度文库 https://wenku.baidu.com/view/6a51abdfcd22bcd126fff705c ...

  2. 非局部均值(Nonlocal-Mean)

    转载自网站:http://www.cnblogs.com/luo-peng/p/4785922.html 非局部均值去噪(NL-means)   非局部均值(NL-means)是近年来提出的一项新型的 ...

  3. 非局部均值去噪(NL-means)

    非局部均值(NL-means)是近年来提出的一项新型的去噪技术.该方法充分利用了图像中的冗余信息,在去噪的同时能最大程度地保持图像的细节特征.基本思想是:当前像素的估计值由图像中与它具有相似邻域结构的 ...

  4. 积分图像的应用(二):非局部均值去噪(NL-means)

    非局部均值去噪(NL-means)一文介绍了NL-means基本算法,同时指出了该算法效率低的问题,本文将使用积分图像技术对该算法进行加速. 假设图像共像个素点,搜索窗口大小,领域窗口大小, 计算两个 ...

  5. stm32_ADC定时器采样(DMA均值处理数据)

    在有些要求高的场合,需要用到定时器采样.本人在网上没找到合适的源码,于是将自己的思路分享出来,欢迎大家提出意见. 确定ADC采用的通道对应的通道 确定采样对应的引脚(这个在规格书的引脚定义部分可以找到 ...

  6. 非局部均值滤波算法的python实现

    如题,比opencv自带的实现效果好 #coding:utf8 import cv2 import numpy as np def psnr(A, B): return 10*np.log(255*2 ...

  7. OpenCV2+入门系列(四):计算图像的直方图,平均灰度,灰度方差

    本篇懒得排版,直接在网页html编辑器编辑 在图像处理时,我们常常需要求出图像的直方图.灰度平均值.灰度的方差,这里给出一个opencv2+自带程序,实现这些功能. 直方图 对于直方图,使用cv::c ...

  8. OpenCV2+入门系列(三):遍历图像的几种方法

    根据OpenCV中Mat类型的结构和内存中存储方式,此处给出三种对图像进行遍历的方法.首先给出基础的读取图片代码,在中间替换三种遍历方法即可,本文中,程序将遍历图像并将所有像素点置为255,所有运行结 ...

  9. OpenCV2类批量处理文件夹及文件图像 及批量处理后保存到txt文件

    //采用windows控制台实现计算文件夹中对象总数以及批量读取对象 //#include <afx.h> //和windows.h是一样的作用 #include <opencv2/ ...

随机推荐

  1. 封装自己的DB类(PHP)

    封装一个DB类,用来专门操作数据库,以后凡是对数据库的操作,都由DB类的对象来实现.这样有了自己的DB类,写项目时简单的sql语句就不用每次写了,直接调用就行,很方便! 1.封装一个DB类.一个类文件 ...

  2. 推荐学习使用cocoapods和phoneGap安装的链接

    phoneGap安装:http://blog.csdn.net/cwb1128/article/details/18019751 cocoaPods使用:http://blog.csdn.net/wz ...

  3. python字符串的使用

    之前在网上看了关于python最基础的一些教程,看着都通俗易懂,但是在写的过程中却感觉还是很生涩.关于字符串的使用还是应该多写多练!如何将“teacher_id = 123 #老师ID”转换成字典或者 ...

  4. C# Winform中如何让PictureBox的背景透明

    最近做winform程序,其中有个需求:有两个PictureBox完全重叠,上面一个需要透明,不能遮挡下面的,以为设置上面的BackColor为透明色就可以了,结果不行,上网搜了一下,发现对于我这种需 ...

  5. Windows安装和使用zookeeper

    之前整理过一篇文章<zookeeper 分布式锁服务>,本文介绍的 Zookeeper 是以 3.4.5 这个稳定版本为基础,最新的版本可以通过官网 http://hadoop.apach ...

  6. Hadoop学习笔记—1.基本介绍与环境配置

    一.Hadoop的发展历史 说到Hadoop的起源,不得不说到一个传奇的IT公司—全球IT技术的引领者Google.Google(自称)为云计算概念的提出者,在自身多年的搜索引擎业务中构建了突破性的G ...

  7. Hibernate的三种状态及对象生命周期

        理解Hibernate的三种状态,更利于理解Hibernate的运行机制,这些可以让你在开发中对疑点问题的定位产生关键性的帮助. 三种状态 临时状态(Transient):在通过new关键字, ...

  8. Unbroken(坚不可摧)——Mateusz M

    Unbroken(坚不可摧)——Mateusz M YouTube励志红人账号Mateusz M 的作品,短片由几位演讲家Les Brown.Eric Thomas.Steve Jobs.Louis ...

  9. EF:自定义Oracle的映射类型

    oracle在DB First模式下,int类型的字段会自动映射为decmial类型的属性. 我们可以通过自定义类型映射进行“纠整”. 在app.config 自定义映射规则: <oracle. ...

  10. C语言 · 图形显示

    问题描述 编写一个程序,首先输入一个整数,例如5,然后在屏幕上显示如下的图形(5表示行数): * * * * * * * * * * * * * * *     #include "stdi ...