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

    MySQL5.6 GTID新特性实践 GTID简介 搭建 实验一:如果slave所需要事务对应的GTID在master上已经被purge了 实验二:忽略purged的部分,强行同步 本文将简单介绍基于 ...

  2. stl文件格式解析代码--java版

    代码是参考three.js中的stlLoader.js写的. 需要注意的地方,java中byte取值-128~127 package test_stl.test_entry; import java. ...

  3. C# 开源组件--Word操作组件DocX

    使用模版生成简历 读写表格数据 合并单元格 工具源代码下载 学习使用 使用模版生成简历 下面将以一个简历实例来讲解DocX对表格的操作,先看看生成的效果 private static void Cre ...

  4. TestNG 与 Junit的比较

    转自 http://www.blogjava.net/fanscial/archive/2005/12/14/23780.html 1.         JDK 5 Annotations (JDK ...

  5. Repeater的分页

      Repeater控件是个好东西.轻量级.又好用.完全的自定义.但是,正是因为这些优点它没有自动分页的功能.这个需要研究一下.我看了一下起点等小说网站,那些什么推荐排名榜用Repeater控件那是很 ...

  6. 详解Maple如何公式推导和生成代码

    公式推导 直观自然的数学表达式,智能的关联菜单,交互式助手等协助您从容通过推导过程,让您更容易地完成解决方案的开发,快速.无错! 分析 Maple 内置超过大量的计算函数,包括积分变换,微分方程求解器 ...

  7. 安卓工具箱:color of Style

    <?xml version="1.0" encoding="utf-8"?> <resources> <color name=&q ...

  8. (C#)使用NPOI导出Excel

    在做业务型的软件时,经常需要将某些数据导出,本文介绍了在Winform或Asp.net中使用NPOI(POI 项目的 .NET 版本)来操作Excel文件,而无需安装Office. 首先,需要获取NP ...

  9. Node.js学习笔记

    相关介绍 1.Node.js或者Node,是一个可以让javascript运行在服务器端的平台. 2.Node.js是一个为实时Web应用开发而诞生的语言,它从诞生之初就充分考虑了再实时响应.超大规模 ...

  10. WCF basicHttpBinding之Transport Security Mode, clientCredentialType="None"

    原创地址:http://www.cnblogs.com/jfzhu/p/4071342.html 转载请注明出处 前面文章介绍了<WCF basicHttpBinding之Message Sec ...