本节内容:

  • 访问像素值
  • 用指针扫描图像
  • 用迭代器扫描图像
  • 编写高效的图像扫描循环
  • 扫描图像并访问相邻像素
  • 实现简单的图像运算
  • 图像重映射

访问像素值

  准备工作:

    创建一个简单函数,用它在图像中加入椒盐噪声.

    实现如下:

void salt(cv::Mat image, int n){
int i, j;
for(int k = ; k < n; k ++){
i = std::rand()%image.cols;
j = std::rand()%image.rows; if(image.type() == CV_8UC1){ //灰度图
image.at<uchar>(j,i) = ;
}else {
image.at<cv::Vec3b>(j,i)[] = ;
image.at<cv::Vec3b>(j,i)[] = ;
image.at<cv::Vec3b>(j,i)[] = ;
}
}
}

    完整代码:

#include <cstdlib>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
void salt(cv::Mat image, int n){
int i, j;
for(int k = ; k < n; k ++){
i = std::rand()%image.cols;
j = std::rand()%image.rows; if(image.type() == CV_8UC1){ //灰度图
image.at<uchar>(j,i) = ;
}else {
image.at<cv::Vec3b>(j,i)[] = ;
image.at<cv::Vec3b>(j,i)[] = ;
image.at<cv::Vec3b>(j,i)[] = ;
}
}
} int main(){
cv::Mat image = cv::imread("./data/rgb.png");
salt(image,);
cv::namedWindow("image");
cv::imshow("Image", image);
cv::waitKey();
cv::imwrite("./data/output.png", image);
return ;
}

    效果如图:

用指针扫描图像

  准备工作:

    先完成一个简单任务:减少图像中的颜色数量。

    原理:如果N是减少因子,那么对于像素的每一个频道,除以N(由于是整除,所以余数会丢失)。如果将结果再乘以N,那么结果将会小于原来的像素值。然后再加上N/2你将会获得两个相邻N倍数中间的那个数,然后你就得到了一个256/NX256/NX256/N颜色数的图像。下面是我们所写的函数,函数处理是in-place的,也就是说处理结果直接赋值给源图像,不占用额外的存储空间。

    代码:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream> void colorReduce(cv::Mat image, int div){
int nl = image.rows;
int nc = image.cols * image.channels(); for(int j = ; j < nl; j++){
uchar* data = image.ptr<uchar>(j);
for(int i = ; i < nc; i++){
data[i] = data[i]/div*div + div/;
}
}
} int main(){
cv::Mat image = cv::imread("./data/beauty.jpg");
colorReduce(image, );
cv::namedWindow("Image");
cv::imshow("Image",image);
cv::waitKey();
cv::imwrite("./data/output.jpg", image);
return ;
}

    补充:还可以使用为运算来计算data的值; 

       uchar mask = 0xFF<<n;             //例如:div = 16,则 mask = 0xF0

       *data &= mask;

       *data++ += div>>1; 

处理前:                             处理后:                 

 

用迭代器扫描图像

  准备工作:仍然使用上面减色程序。

       使用Mat_模板类内部定义的iterator类型 Mat_<cv::Vec3b>::iterator it;

  修改后的减色程序如下:

void colorReduce(cv::Mat &image, int div){
cv::Mat_<cv::Vec3b>::iterator it = image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::iterator itend = image.end<cv::Vec3b>();
for( ; it != itend; ++it){
(*it)[] = (*it)[]/div*div + div/;
(*it)[] = (*it)[]/div*div + div/;
(*it)[] = (*it)[]/div*div + div/;
}
}

  效果同上;

编写高效的图像扫描循环

  

在前面的章节,我们已经提到过了不同的访问图像像素的方法。现在我们将比较一下这些不同方法的效率。因为代码的效率执行时间是我们必须要考虑的。但是代码效率最大化带来来的往往是减少了代码的可读性。所以只要适当的在核心地方增加代码的效率。

为了计算代码的执行时间,我们使用OpenCV中的cv::getTickCount()方法。这个方法给出从开机到现在的时钟周期数。因为我们想要的时间单位是毫秒,所以我们还要使用cv::getTickFrequency()方法。这个给出了每一秒的始终周期数。然后计算方法如下:

double duration;
duration = static_cast<double>(cv::getTickCount());
colorReduce(image); // the function to be tested
duration = static_cast<double>(cv::getTickCount())-duration;
duration /= cv::getTickFrequency(); // the elapsed time in ms

最后得出的结果是:使用位计算得到的结果速度最快!

扫描图像并访问相邻像素

  准备工作:

     这里使用一个锐化的处理函数. 如果从图像中减去拉普拉斯算子部分,图像的边缘就会放大,因而使图像更尖锐.

    用以下的方法计算锐化的数值:  sharpened_pixel = 5 * current -left - right - up -down;

  实现:

/********************************************************
> File name:sharpen
> author: yoyo
> Source from:xiang gao
> time:2016.7.18 Monday 17:22
>
*************************************************************/ #include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream> using namespace std; void sharpen(const cv::Mat &image, cv::Mat &result){
//判断是否需要分配图像数据
result.create(image.size(), image.type());
int nchannels = image.channels(); //获取通道数 //处理除第一与最后行的所有行
for(int j = ; j < image.rows-; j++){
const uchar* previous = image.ptr<const uchar>(j-);
const uchar* current = image.ptr<const uchar>(j);
const uchar* next = image.ptr<const uchar>(j+);
uchar* output = result.ptr<uchar>(j); for(int i = nchannels; i < (image.cols - )*nchannels; i++){
*output++ = cv::saturate_cast<uchar>(*current[i] - current[i-nchannels] - current[i+nchannels] -previous[i] -next[i]);
}
}
result.row().setTo(cv::Scalar());
result.row(result.rows-).setTo(cv::Scalar());
result.col().setTo(cv::Scalar());
result.col(result.cols-).setTo(cv::Scalar());
} int main(int argc, char * argv[]){ cv::Mat image = cv::imread("/home/yoyo/openCV/data/beauty.jpg");
cv::Mat image1 = image;
cv::imshow("image1", image1);
sharpen(image1 ,image);
// cv::namedWindow("image");
cv::imshow("Image", image);
cv::waitKey();
cv::imwrite("/home/yoyo/openCV/data/sharpen.jpg", image);
return ;
}

  效果:

    前:                      后:

                      

实现简单的图像运算

  图像就是普通的矩阵,可以进行加减乘除运算,因此可以用多种不同的方式组合图像.

  准备工作:两张相等大小的图像;

  参考资料:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/core/adding_images/adding_images.html

  代码:

#include <cv.h>
#include <highgui.h>
#include <iostream> using namespace cv; int main( int argc, char** argv )
{
double alpha = 0.5; double beta; double input; Mat src1, src2, dst; /// Ask the user enter alpha
std::cout<<" Simple Linear Blender "<<std::endl;
std::cout<<"-----------------------"<<std::endl;
std::cout<<"* Enter alpha [0-1]: ";
std::cin>>input; /// We use the alpha provided by the user iff it is between 0 and 1
if( alpha >= && alpha <= )
{ alpha = input; } /// Read image ( same size, same type )
src1 = imread("../../images/LinuxLogo.jpg");
src2 = imread("../../images/WindowsLogo.jpg"); if( !src1.data ) { printf("Error loading src1 \n"); return -; }
if( !src2.data ) { printf("Error loading src2 \n"); return -; } /// Create Windows
namedWindow("Linear Blend", ); beta = ( 1.0 - alpha );
addWeighted( src1, alpha, src2, beta, 0.0, dst); imshow( "Linear Blend", dst ); waitKey();
return ;
}

图像重映射

OpenCV 学习之路(2) -- 操作像素的更多相关文章

  1. opencv学习之路(15)、形态学其他操作(开、闭、顶帽、黑帽、形态学梯度)

    一.形态学其他操作(用的不多,如果忘了也可以通过膨胀腐蚀得到相同效果) 1.开运算 2.闭运算 3.形态学梯度 4.顶帽 5.黑帽 #include "opencv2/opencv.hpp& ...

  2. opencv学习之路(5)、鼠标和滑动条操作

    一.鼠标事件 #include<opencv2/opencv.hpp> #include<iostream> using namespace cv; using namespa ...

  3. opencv学习之路(38)、Mat像素统计基础——均值,标准差,协方差;特征值,特征向量

    本文部分内容转自 https://www.cnblogs.com/chaosimple/p/3182157.html 一.统计学概念 二.为什么需要协方差 三.协方差矩阵 注:上述协方差矩阵还需要除以 ...

  4. opencv学习之路(7)、访问图像像素

    一.动态地址访问 #include <opencv2/opencv.hpp> #include<iostream> using namespace cv; using name ...

  5. OpenCV 学习笔记(11)像素级别指针操作

    //优化两图的连接处,使得拼接自然 void OptimizeSeam(Mat& img1, Mat& trans, Mat& dst) { int start = MIN(c ...

  6. opencv学习之路(31)、GrabCut & FloodFill图像分割

    一.GrabCut 1.利用Rect做分割 #include "opencv2/opencv.hpp" using namespace cv; void main() { Mat ...

  7. Opencv学习之路—Opencv下基于HOG特征的KNN算法分类训练

    在计算机视觉研究当中,HOG算法和LBP算法算是基础算法,但是却十分重要.后期很多图像特征提取的算法都是基于HOG和LBP,所以了解和掌握HOG,是学习计算机视觉的前提和基础. HOG算法的原理很多资 ...

  8. opencv学习之路(40)、人脸识别算法——EigenFace、FisherFace、LBPH

    一.人脸识别算法之特征脸方法(Eigenface) 1.原理介绍及数据收集 特征脸方法主要是基于PCA降维实现. 详细介绍和主要思想可以参考 http://blog.csdn.net/u0100066 ...

  9. opencv学习之路(32)、角点检测

    一.角点检测的相关概念 二.Harris角点检测——cornerHarris() 参考网址: http://www.cnblogs.com/ronny/p/4009425.html #include ...

随机推荐

  1. [LA3523/uva10195]圆桌骑士 tarjan点双连通分量+奇环定理+二分图判定

    1.一个环上的各点必定在同一个点双连通分量内: 2.如果一个点双连通分量是二分图,就不可能有奇环: 最基本的二分图中的一个环: #include<cstdio> #include<c ...

  2. PHP 练习3:租房子

    一.题目要求 二.题目做法 1.建立数据库 2.封装类文件 <?php class DBDA { public $fuwuqi="localhost"; //服务器地址 pu ...

  3. ios的app,有新版本时必须先更新。

    现在没时间整理,先把代码贴出来,以后再做详细的思路整理. 1 在AppController.mm的didFinishLaunchingWithOptions方法里面获取本地应用版本信息,保存起来. / ...

  4. 老生常谈-Activity(山东数漫江湖)

    对于activity的七个声生命周期回调,总是被大家翻来覆去的说,甚至说的都有些厌烦了,这部分知识虽然基础但也很重要,谁都不想在面试的时候只说出个一知半解,下面的分析是对阅读<安卓开发艺术探索& ...

  5. Python ctypes的byref和pointer有啥区别

    byref(n)返回的相当于C的指针右值&n,本身没有被分配空间: >>> from ctypes import *>>> n = c_int(0)> ...

  6. 【shell】shell中各种括号的作用()、(())、[]、[[]]、{}

    一.小括号,圆括号() 1.单小括号 ()    ①命令组.括号中的命令将会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用.括号中多个命令之间用分号隔开,最后一个命令可以没有 ...

  7. 自动化测试===unittest配套的HTMLTestRunner.py生成html报告源码

    更改版: 全部复制,命名为  HTMLTestRunner.py 文件 #使用方法参见之前的文档:自动化测试===unittest和requests接口测试案例,测试快递查询api(二) " ...

  8. NOIP 2013 day2

    tags: 模拟 贪心 搜索 动态规划 categories: 信息学竞赛 总结 积木大赛 花匠 华容道 积木大赛 Solution 发现如果一段先单调上升然后在单调下降, 那么这一块的代价是最高的减 ...

  9. java虚拟机字节码执行引擎

    定义 java虚拟机字节码执行引擎是jvm最核心的组成部分之一,它做的事情很简单:输入的是字节码文件,处理过程是字节码解析的等效过程,输出的是执行结果.在不同的虚拟机实现里,执行引擎在执行java代码 ...

  10. scala中常用特殊符号

    参考资料: scala中常用但其他语言不常见的符号含义 Scala学习六:Scala中的特殊字符 =>(匿名函数) 参考文档:scala => 用法 匿名函数 => 匿名函数,在Sp ...