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/ ...
随机推荐
- Java中堆内存和栈内存详解
Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间 ...
- Code First开发系列之管理并发和事务
返回<8天掌握EF的Code First开发>总目录 本篇目录 理解并发 理解积极并发 理解消极并发 使用EF实现积极并发 EF的默认并发 设计处理字段级别的并发应用 实现RowVersi ...
- 操作系统核心原理-7.设备管理:I/O原理
一.I/O的基本知识 1.1 为何要有I/O 前面阐述了操作系统具有进程管理.内存管理.外存管理三大核心功能,但是计算机归根是为人类服务的,这就要求计算机必须提供某种机制使得人们可以向计算机发出命令或 ...
- HappyAA服务器部署笔记2(nginx的静态资源缓存配置)
我近期对服务器进行了少量改进,虽然之前使用了nginx反向代理之后性能有所提高,但仍然不够,需要使用缓存来大幅度提高静态资源的访问速度. 服务器上的静态资源主要有这些:png, jpg, svg, j ...
- Atom使用纪要
一直在更新的原文地址奉上,欢迎PR:Atom使用纪要 官网地址: atom.io 目前(2015/7/29)Atom主题已有725个:Package已有2394 简单交代背景 Atom 是 Githu ...
- Windows Azure Storage (23) 计算Azure VHD实际使用容量
<Windows Azure Platform 系列文章目录> 对于A系列和D系列的虚拟机来说,使用的是普通存储. 普通存储的存储资源,是按照每GB每月计费的.Microsoft Azur ...
- Dash文档制作教程
前言 什么是Dash 面向程序员的文档库(Mac) 代码片段管理工具 这是强烈推荐给每天在各种API文档中摸爬滚打的程序员们的神器. 为什么要自己制作文档 官方的源中没有相关文档 文档在离线下体验更好 ...
- hibernate学习笔记之四 Hibernate的增删改查
采用JUnit测试,继承TestCase import java.util.Date; import junit.framework.TestCase; import org.hibernate.Se ...
- [oracle]逗号(或分号等)间隔的列,按这一列劈分后转多行
今天遇到个需求,要匹配两个表, 但是关联的字段,在另一个表中是放在一个字段中用分号分割的 怎么全部匹配呢? 后来在网上搜到了, 记录下 SELECT cp.ES_EXTNUMBER, cp.ES_AG ...
- Java final 关键词修饰类、方法、变量
1. final修饰类 被修饰的类不能被继承,也没有子类.假如随意创建这些类的子类,子类可能会错误的修改父类的实现细节.出于安全原因,类的实现细节不允许有任何改动.在创建对象模型的时候,确信这个类不 ...