现在的位置: 首页 > 综合 > 正文

像素级的图像处理—opencv.2学习笔记1

2013年06月11日 ⁄ 综合 ⁄ 共 4612字 ⁄ 字号 评论关闭

一、图像中对像素的操作

#include "stdafx.h"
#include <stdio.h>
using namespace std;
using namespace cv;

void salt(Mat &image,int n)
{
	for(int k = 0;k < n;k++)
	{
		int i = rand() % image.cols;
		int j = rand() % image.rows;
		if(image.channels() == 1)
			image.at<uchar>(j,i) = 255;
		else if(image.channels() == 3)
		{
			image.at<Vec3b>(j,i)[0] = 255;
			image.at<Vec3b>(j,i)[1] = 255;
			image.at<Vec3b>(j,i)[2] = 255;
		}
	}
}

void main()
{	
	Mat image = imread("E:\\1.jpg");

	namedWindow("img");
	imshow("img",image);

	salt(image,3000);

	namedWindow("image");
	imshow("image",image);
	waitKey(0);
}

配置:opencv2.4.1+vs2010

代码说明:在像素级别上对图像进行处理,显示了掓盐噪声对图像的影响。椒盐噪声是由图像传感器,传输信道,解码处理等产生的黑白相间的亮暗点噪声。椒盐噪声往往由 图像切割引起。去除脉冲干扰及椒盐噪声最常用的算法中值滤波

函数说明:cv::Mat中的at(int y,int x)

但是在代码中我们可以看到他的形式是:image.at<Vec3b>(j,i)[0] = 255;  

      1. 这是为模板类型的函数,因为一个函数的返回类型只有在运行时才会知道。

      2.这个函数返回的是一个向量即Vector,故有下标的操作。

      3.<Vec3b>代表的意思是:a vector of three 8-bit value。也可以是Vec2b,Vec4b

      4.调用模板类型的at()函数有时是效率不高的,因为它的返回类型每次都要由传递的一个模板参数来确定。所以当矩阵的类型已知时,如一个 uchar Matrix,可以利用Mat_类

则 cv::Mat_<uchar> im2= image; // im2 refers to image
      im2(50,100)= 0; // access to row 50 and column 100

     5、该函数不用于扫描图像,因为效率低,一般用于随机访问像素

            

处理效果图:

 

二、用指针扫描图像

代码1:

#include "stdafx.h"
using namespace std;
using namespace cv;

void colorReduce(Mat &img,int div = 128)
{
	int nl = img.rows;
	int nc = img.cols * img.channels();

	for(int j = 0;j < nl;j++)
	{
		uchar *data = img.ptr<uchar>(j);
		for(int i = 0;i < nc;i++)
		{
			data[i] = data[i]/div*div + div/2;
		}
	}
}

void main()
{	
	Mat image = imread("E:\\1.jpg");

	namedWindow("img");
	imshow("img",image);

	Mat imageClone = image.clone();
	colorReduce(imageClone);

	namedWindow("imageClone");
	imshow("imageClone",imageClone);
	waitKey(0);
}

代码2:

#include "stdafx.h"
using namespace std;
using namespace cv;

void colorReduce(const Mat &img,Mat &result,int div = 128)
{
	int nl = img.rows;
	int nc = img.cols * img.channels();

	for(int j = 0;j < nl;j++)
	{
		const uchar *data_in = img.ptr<uchar>(j);
		uchar *data_out = result.ptr<uchar>(j);
		for(int i = 0;i < nc;i++)
		{
			data_out[i] = data_in[i]/div*div + div/2;
		} 
	}
}

void main()
{	
	Mat image = imread("E:\\1.jpg");

	namedWindow("img");
	imshow("img",image);

	Mat result;
	result.create(image.rows,image.cols,image.type());

	colorReduce(image,result);

	namedWindow("imageClone");
	imshow("imageClone",result);
	waitKey(0);
}

代码3:当图像的数据存储是连续的,即每个像素值的存储之间没有进行过填充,我们可以用一种更高效的访问方式

#include "stdafx.h"
using namespace std;
using namespace cv;

void colorReduce( Mat &img,int div = 128)
{
	if(img.isContinuous())
	{
		img.reshape(1,img.cols*img.rows);
	}
	int nl = img.rows;
	int nc = img.cols * img.channels();

	for(int j = 0;j < nl;j++)
	{
		uchar *data = img.ptr<uchar>(j);
		for(int i = 0;i < nc;i++)
		{
			data[i] = data[i]/div*div + div/2;
		} 
	}
}

void main()
{	
	Mat image = imread("E:\\1.jpg");

	namedWindow("img");
	imshow("img",image);
	
	Mat imageClone = image.clone();
	colorReduce(imageClone);

	namedWindow("imageClone");
	imshow("imageClone",imageClone);
	waitKey(0);
}

代码说明:以上三个程序完成的都是利用指针扫描图片,并实现图像颜色空间的压缩。

压缩方法:1、data[i]= data[i]/div*div + div/2; 2、data[i]=    data[i] – data[i]%div + div/2;   对于第一种当div=pow(2,n)时可以用移位操作:uchar mask= 0xFF<<n;data[i]=    (data[i]&mask) + div/2;

函数说明:

代码1:ptr(int j) //它是一个模板函数,返回图像矩阵的第j行的首地址

              image.clone() //用于克隆一张图片,但是会产生额外的开销

代码2:

            result.create(image.rows,image.cols,image.type());//创建一幅与image同大小及同类型的图像,实际分配内存空间;

//代码2的作用是,不管使用者是否提供两张图片,函数colorReduce(const Mat &img,Mat &result,int div = 128)都能正常工作,且源图像保证不会被改变
代码3:isContinuous()) //用于判断图像的存储是否连续的

               reshape(1,img.cols*img.rows)  //重新进行图像的维数调整,第一个参数:图像的通道,第二参数:图像的行数。该操作不进行任何的内存拷贝或分配
原图:

处理效果图:

 

三、利用迭代器遍历图像的像素

void colorReduce( Mat &img,int div = 128)
{
	Mat_<cv::Vec3b>::iterator it = img.begin<cv::Vec3b>();
	Mat_<cv::Vec3b>::iterator itend = img.end<cv::Vec3b>();
	while(it != itend)
	{
		(*it)[0] = (*it)[0]/div*div + div/2;
		(*it)[1] = (*it)[1]/div*div + div/2;
		(*it)[2] = (*it)[2]/div*div + div/2;
		++it;
	}
}

说明:两种方法定义迭代器 1、cv::Mat_<cv::Vec3b>::iterator it;  2、cv::MatIterator_<cv::Vec3b> it;

定义静态迭代器:1、cv::Mat_<cv::Vec3b>::const_iterator it;  2、cv::MatConstIterator_<cv::Vec3b> it;

四、执行时间计时及以上情况的访问速度比较

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

函数说明:getTickCount()  //获得当前的时钟周期数

                 getTickFrequency()  //机器每秒执行的时钟周期数

 

五、图像颜色空间压缩的最快的一种代码方式

void colorReduce(cv::Mat &image, int div=64) {
     int nl= image.rows; // number of lines
     int nc= image.cols ; // number of columns
     // is it a continous image?
     if (image.isContinuous())  {
        // then no padded pixels
        nc= nc*nl; 
        nl= 1;  // it is now a 1D array
      }
     int n= static_cast<int>(
              log(static_cast<double>(div))/log(2.0));
     // mask used to round the pixel value
     uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
     // for all pixels         
     for (int j=0; j<nl; j++) {
          // pointer to first column of line j
          uchar* data= image.ptr<uchar>(j);
          for (int i=0; i<nc; i++) { 
            // process each pixel ---------------------
            *data++= *data&mask + div/2;
            *data++= *data&mask + div/2;
            *data++= *data&mask + div/2;
            // end of pixel processing ----------------          } // end of line                   
     }
}

 

抱歉!评论已关闭.