zoukankan      html  css  js  c++  java
  • OpenCV2:幼儿园篇 第四章 访问图像

    一.行/列访问

    1.单行/单列访问

    Mat Mat::row(int i) const

    Mat Mat::col(int j) const

    2.多行/多列访问

    Range(start,end);

    Range::all();  // 表示所有行或列

    Mat A;
    Mat B=A(Range::(5,9),Range(1,3));  //表示5-9行(不包括9),1-3列(不包括3)
    

    二.区域访问

    1.CRect

    //在图像的右下角定义一个ROI
    cv::Mat imageROI(image,cv::Rect(image.cols-logo.cols,
                                    image.rows-logo.rows,
                                    logo.cols,
                                    logo.rows));
     
     
    或者
    cv::Mat imageROI=image(cv::Rect(image.cols-logo.cols,
                                    image.rows-logo.rows,
                                    logo.cols,
                                    logo.rows));
    

    2.CSize

    三.像素访问

    1.at()访问

    使用at()函数代码可读性高,效率不是很高,使用at()函数必须用两个循环实现

    注意访问顺序,先访问行(外循环rows)(指针在高的第一行)

                          再访问列(内循环cols)(指针移动宽的每一行)

    template <typename _Tp> inline _Tp& Mat::at(int i0, int i1)

    template <typename _Tp> inline const _Tp& Mat::at(int i0, int i1) const

    template <typename _Tp> inline _Tp& Mat::at(Point pt)

    template <typename _Tp> inline const _Tp& Mat::at(Point pt) const

    template <typename _Tp> inline _Tp& Mat::at(int i0)

    template <typename _Tp> inline const _Tp& Mat::at(int i0) const

    template <typename _Tp> inline _Tp& Mat::at(int i0, int i1, int i2)

    template <typename _Tp> inline const _Tp& Mat::at(int i0, int i1, int i2) const

    template <typename _Tp> inline _Tp& Mat::at(const int* idx)

    template <typename _Tp> inline const _Tp& Mat::at(const int* idx) const

    template <typename _Tp, int n> _Tp& Mat::at(const Vec<int, n>& idx)

    template <typename _Tp, int n> inline const _Tp& Mat::at(const Vec<int, n>& idx) const

    at()函数是模板函数,可以自定义类型

    其中at<uchar>表示单通道图像,at<cv::Vec3b>表示三通道图像

    //遍历像素值
     
    #include <iostream>
    #include "opencv2/opencv.hpp"
     
    using namespace std;
     
    int main(int argc, char* argv[]) {
     
    	cv::Mat grayim(600, 800, CV_8UC1);
    	cv::Mat colorim(600, 800, CV_8UC3);
     
    	//遍历所有像素,并设置像素值
    	for(int i = 0;i < grayim.rows; ++i)
    		for(int j = 0; j < grayim.cols; ++j)
    			grayim.at<uchar>(i,j) = (i+j)%255;
     
    	//遍历所有像素,并设置像素值
    	for(int i=0; i<colorim.rows; ++i)
    		for(int j=0; j<colorim.cols; ++j)
    		{
     
    			cv::Vec3b pixel;
    			pixel[0] = i%255;  //Blue
    			pixel[1] = j%255;  //Green
    			pixel[2] = 0;      //Red
    			colorim.at<cv::Vec3b>(i,j) = pixel;
    		}
     
    	cv::imshow("grayim",grayim);
    	cv::imshow("colorim",colorim);
     
    	cv::waitKey(0);
     
    	return 0;
     
    }
    

    2.ptr()访问

    注意at()函数返回的是一个uchar变量类型,而ptr()函数返回的是一个uchar*指针类型

    ptr()函数和at()函数都需要两个循环来遍历像素.虽然它返回的是指针,索引速度比较快,但是指针不进行类型以及越界检查

    它的访问顺序是跟at()函数有点像,先获取首个行指针,再遍历列指针

    inline uchar* Mat::ptr(int y)

    inline const uchar* Mat::ptr(int y) const

    template<typename _Tp> inline _Tp* Mat::ptr(int y)

    template<typename _Tp> inline const _Tp* Mat::ptr(int y) const

    inline uchar* Mat::ptr(int i0, int i1)

    intline const uchar* Mat::ptr(int i0, int i1) const

    template<typename _Tp> inline _Tp* Mat::ptr(int i0, int i1)

    template<typename _Tp> inline const _Tp* Mat::ptr(int i0, int i1) const

    inline uchar* Mat::ptr(int i0, int i1, int i2)

    inline const uchar* Mat::ptr(int i0, int i1, int i2) const

    template<typename _Tp> inline _Tp* Mat::ptr(int i0, int i1, int i2)

    template<typenmae _Tp> inline const _Tp* Mat::ptr(int i0, int i1, int i2) const

    inline uchar* Mat::ptr(const int* idx)

    inline const uchar* Mat::ptr(const int* idx) const

    #include <iostream>
    #include "opencv2/opencv.hpp"
     
    using namespace std;
     
    int main(int argc, char* argv[]) {
     
    	cv::Mat grayim(600,800,CV_8UC1);
    	cv::Mat colorim(600,800,CV_8UC3);
     
    	//遍历所有像素,并设置像素值
    	for( int i = 0; i < grayim.rows; ++i) {
     
    		//获取第i行首像素指针
    		uchar* p = grayim.ptr<uchar>(i);
     
    		//对第i的每个像素操作
    		for(int j = 0;j < grayim.cols; ++j)
    			p[j] = (i+j)%255;
    	}
     
    	//遍历所有像素,并设置像素值
    	for( int i = 0; i<colorim.rows; ++i) {
     
    		//获取第i行首像素指针
    		cv::Vec3b* p=colorim.ptr<cv::Vec3b>(i);
    		for( int j = 0; j < colorim.cols; ++j) {
    			p[j][0] = i%255;  //Blue
    			p[j][1] = j%255;  //Green
    			p[j][2] = 0;     //Red
    		}
    	}
     
    	imshow("grayim", grayim);
    	imshow("colorim", colorim);
    	cv::waitKey(0);
     
    	return 0;
    }
    

    3.迭代器访问

    迭代器访问有点像at()函数访问,虽然它只需要一个循环,但是它的可读性没有at()函数清楚

    MatIterator_是一个类模板,而at()函数是函数模板

    MatIterator_类似于STL中的迭代器,根据迭代器开头和结尾一直遍历

    template<typename _Tp>

    class MatIterator_ : public MatConstIterator_<_Tp>

    {

    public:

      typedef _Tp* pointer;

      typedef _Tp& reference;

      typedef std::random_access_iterator_tag iterator_category;

      

      MatIterator_();

      MatIterator_(Mat_<_Tp>* _m);

      MatIterator_(Mat_<_Tp>* _m, int _row, int _col = 0);

      MatIterator_(const Mat_<_Tp>* _m, Point _pt);

      MatIterator_(const Mat_<_Tp>* _m, const int* _idx);

      MatIterator_(const MatIterator_& it);

      MatIterator_& operator = (const MatIterator_<_Tp>& it);

      _Tp& operator *() const;

      _Tp& operator [](ptrdiff_t i) const;

      MatIterator_& operator += (ptrdiff_t ofs);

      MatIterator_& operator -= (ptrdiff_t ofs);

      MatIterator_& operator -- ();

      MatIterator_  operator --  (int);

      MatIterator_& operator ++ ();

      MatIterator_  operator ++ (int);

    };

    #include <iostream>
    #include "opencv2/opencv.hpp"
     
    using namespace std;
     
    int main(int argc, char* argv[]) {
     
    	cv::Mat grayim(600, 800, CV_8UC1);
    	cv::Mat colorim(600, 800, CV_8UC3);
     
    	//遍历所有像素,并设置像素值
    	cv::MatIterator_<uchar> grayit, grayend;
     
    	for( grayit = grayim.begin<uchar>(), grayend = grayim.end<uchar>(); grayit != grayend; ++grayit)
    		*grayit = rand()%255;
     
    	//遍历所有像素,并设置像素值
    	cv::MatIterator_<cv::Vec3b> colorit,colorend;
     
    	for( colorit = colorim.begin<cv::Vec3b>(), colorend = colorim.end<cv::Vec3b>(); colorit != colorend; ++colorit) {
     
    		(*colorit)[0] = rand()%255;  //Blue
    		(*colorit)[1] = rand()%255;  //Green
    		(*colorit)[2] = rand()%255;  //Red
    	}
     
    	//显示结果
    	cv::imshow("grayim", grayim);
    	cv::imshow("colorim", colorim);
    	
    	cv::waitKey(0);
     
    	return 0;
     
    }
    

    4.模板访问

    //用Mat_模板操作图像
    cv::Mat_<uchar> im2(image);
    im2(50,100)=0;  // 访问第50行,第100列处那个值
    

    5.查找表访问

    LUT(Look Up Table,查找表)是一张像素灰度值的映射表,它将采样到的灰度值经过图像处理(替换 反转  赋值 阈值 二值化 灰度变化等),利用映射关系变换成相应的灰度值

    OpenCV中LUT查找表包含256个元素,应用于单通道或相同类型的多通道数据,用于减少图像映射的时间复杂度

    cv::Mat inverseColor6(cv::Mat srcImage)
    {
    
    	int row = srcImage.rows;
    	int col = srcImage.cols;
    	cv::Mat tempImage = srcImage.clone();
    
    	// 建立LUT 反色table
    	uchar LutTable[256];
    	for (int i = 0; i < 256; ++i)
    		LutTable[i] = 256 - i;
    
    	cv::Mat lookUpTable(1, 256, CV_8U);
    	uchar* pData = lookUpTable.data;
    
    	// 建立映射表
    	for (int i = 0; i <256; ++i)
    		pData[i] = LutTable[i];
    
    	// 应用搜索表进行查找
    	cv::LUT(srcImage, lookUpTable, tempImage);
    
    	return tempImage;
    }
    

    四.例子

    1.减色

    (1)指针
    //test.cpp
     
    void colorReduce(cv::Mat image,int div=64){
     
    	int nl=image.rows;  //行数
     
    	//每行的元素数量
    	int nc=image.cols*image.channels();
     
    	for(int j=0;j<nl;j++){
     
    		//取得行j的地址
    		uchar* data=image.ptr<uchar>(j);
     
    		for(int i=0;i<nc;i++){
     
    			//处理每个像素
    			data[i]=data[i]/div*div+div/2;
     
    		}
    		
    	}
     
    }
    
     
     (2)迭代器
    void colorReduce(cv::Mat image,int div=64){
     
    	//在初始位置获得迭代器
    	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)[0]=(*it)[0]/div*div+div/2;
    		(*it)[1]=(*it)[1]/div*div+div/2;	
    		(*it)[2]=(*it)[2]/div*div+div/2;
     
    	}
     
    }
    

    2.锐化

    void sharpen(const cv::Mat& image,cv::Mat& result){
    
    	//判断是否需要分配图像数据,如果需要,就分配
    	result.create(image.size(),image.type());
    	int nchannels=image.channels();		//获得通道数
    
    	//处理所有行(除了第一行和最后一行)
    	for(int j=1;j<image.rows-1;j++){
    
    		const uchar* previous=image.ptr<const uchar>(j-1);  //上一行
    		const uchar* current=image.ptr<const uchar>(j);	   //当前行
    		const uchar* next=image.ptr<const uchar>(j+1);	   //下一行
    
    		uchar* output=result.ptr<uchar>(j);					//输出行
    
    		for(int i=nchannels;i<(image.cols-1)*nchannels;i++){
    
    			*output++=cv::saturate_cast<uchar>(
    				5*current[i]-current[i-nchannels]-current[i+nchannels-previous[i]-next[i]]);
    
    
    		}
    	}
    
    	//把未处理的像素设为0
    	result.row(0).setTo(cv::Scalar(0));
    	result.row(result.rows-1).setTo(cv::Scalar(0));
    	result.col(0).setTo(cv::Scalar(0));
    	result.col(result.cols-1).setTo(cv::Scalar(0));
    
    }
    
    
    
    int main()
    {
    	
    
    	cv::Mat imag1=cv::imread("a.jpg");
    	cv::Mat result;
    
    	sharpen(imag1,result);
    
    	cv::namedWindow("Image");
    	cv::imshow("Image",result);
    
    
    	cv::waitKey(0);
    
    	system("pause");
    	return 0;
    }
    
  • 相关阅读:
    Windows 平台下的Mysql集群主从复制
    IOS 的loadView 及使用loadView中初始化View注意的问题。(死循环并不可怕)
    【2013625】K2+SAP集成应用解决方案在线研讨会
    to_char 和 to_date 经验分享
    Java向Access插入数据
    spring Bean的生命周期管理
    [置顶] 30分钟,让你成为一个更好的程序员
    Spring框架中Bean的生命周期
    Box2D的相关知识
    第八周项目二
  • 原文地址:https://www.cnblogs.com/k5bg/p/11077032.html
Copyright © 2011-2022 走看看