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

    gem install  rdiscount -- --use-system-libraries

  2. IOS网络第七天WebView-04仿网易新闻详情

    *************** #import "HMViewController.h" @interface HMViewController () @end @implemen ...

  3. ruby 访问新浪微博API post方式和get方式

    require 'net/https' require 'uri' def post_api(api, args) uri = URI.parse api http = Net::HTTP.new(u ...

  4. CYQ.Data.Orm.DBFast 新增类介绍(含类的源码及新版本配置工具源码)

    前言: 以下功能在国庆期就完成并提前发布了,但到今天才有时间写文介绍,主要是国庆后还是选择就职了,悲催的是上班的地方全公司都能上网,唯独开发部竟不让上网,是个局域网. 也不是全不能上,房间里有三台能上 ...

  5. ES6中的模板字符串和新XSS Payload

    ES6中的模板字符串和新XSS Payload 众所周知,在XSS的实战对抗中,由于防守方经常会采用各种各样严格的过滤手段来过滤输入,所以我们使用的XSS Payload也会根据实际情况作出各种各样的 ...

  6. Hadoop学习笔记—2.不怕故障的海量存储:HDFS基础入门

    一.HDFS出现的背景 随着社会的进步,需要处理数据量越来越多,在一个操作系统管辖的范围存不下了,那么就分配到更多的操作系统管理的磁盘中,但是却不方便管理和维护—>因此,迫切需要一种系统来管理多 ...

  7. log4j.xml的实用例子

    大多数讲log4j配置的教程用的都是log4j.properties文件,我觉得xml或许更好一点,在这里我提供一个我已经用于生产环境的log4j.xml的例子,先上代码,然后再解释: <?xm ...

  8. java中文乱码解决之道(二)-----字符编码详解:基础知识 + ASCII + GB**

    在上篇博文(java中文乱码解决之道(一)-----认识字符集)中,LZ简单介绍了主流的字符编码,对各种编码都是点到为止,以下LZ将详细阐述字符集.字符编码等基础知识和ASCII.GB的详情. 一.基 ...

  9. [nRF51822] 13、浅谈nRF51822和NRF24LE1/NRF24LU1/NRF24L01经典2.4G模块无线通信配置与流程

    前言:  nRF51可以支持基于2.4G的互相通信.与NRF24LE1的通信.与NRF24LU1的通信.与NRF24L01的通信. 一.nRF51822基于2.4G和nRF51822通信 其中nRF5 ...

  10. Android学习——windows下搭建Cygwin环境

    在上一篇博文<Android学习——windows下搭建NDK_r9环境>中,我们详细的讲解了在windows下进行Android NDK开发环境的配置,我们也讲到了在NDk r7以后,我 ...