1.imread
cv::Mat img;
img = cv::imread(image_path, CV_LOAD_IMAGE_COLOR); // image_path为图片存储路径
if (!img.data || !seg.data) {
std::cout << "Could not open or find file " << image_path << std::endl;
return;
}
2.单个像素的操作
a single channel grey scale image (type 8UC1) and pixel coordinates x and y:
int b = (int) img.at<uchar>(y, x); // 占一个字节:uchar, 占四个字节:float。
// opencv Mat 是按行存的。
three channel image with BGR color ordering
---未经验证
cv::Vec3b intensity = img.at<cv::Vec3b>(y, x);
...
#include <stdint.h>
#include <algorithm>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include <fstream>
#include <iostream>
#include <sstream>
#include <math.h>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
int main(){
cv::Mat img ;
cv::Mat dsm ;
std::string image_path = "top_mosaic_09cm_area1.tif" ; // uint8, 三个通道
std::string dsm_path = "dsm_09cm_matching_area1.tif" ; // single, 单通道的
img = cv::imread( image_path, CV_LOAD_IMAGE_COLOR );
dsm = cv::imread( dsm_path, CV_LOAD_IMAGE_UNCHANGED ) ;
if (!img.data || !dsm.data) {
std::cout << "Could not open or find file " << image_path << " or " << dsm_path << std::endl ;
return 1 ;
}
std::cout << "top.channels= " << img.channels() << std::endl ;
std::cout << "dsm.channels= " << dsm.channels() << std::endl ;
std::cout << "dsm.rows=" << dsm.rows << " dsm.cols = " << dsm.cols << std::endl ;
cv::Mat img_concate( 2569, 1919, CV_32FC(4), cv::Scalar::all(0) ) ;
const uchar* img_ptr;
const float* dsm_ptr; // 注意数据类型
int top_index;
for ( int h=0; h<img.rows; h++)
{
img_ptr = img.ptr<uchar>(h); // 读取一行。每行存储方式:每个点三通道连续读:bgr bgr bgr ... 存储方式。
dsm_ptr = dsm.ptr<float>(h); // the data type should be right
int img_index = 0;
int dsm_index = 0;
for ( int w=0; w<img.cols; w++)
{
for ( int c=0; c<3; c++ ){
top_index = (c*img.rows + h )*img.cols + w ;
float pixel = float ( img_ptr[ img_index++ ] ) ;
img_concate.data[ top_index ] = pixel ;
// std::cout << "img concate " << float ( img_concate.data[ top_index ] ) << std::endl ; // Mat数据,转化类型后再输出
}
top_index = ( 3*img.rows + h ) * img.cols + w ; // 第四个通道上(h,w)位置上的索引, img_concate
float pixel = dsm_ptr[ dsm_index++ ] ;
img_concate.data[ top_index ] = pixel ; // 存第四个通道上的数值
// std::cout << "img concate " << float ( img_concate.data[ top_index ] ) << std::endl;
}
}
std::cout << "hello, world!" << std::endl ;
return 1;
}
3.resize
cv::Size rescaleSize( resize_w, resize_h );
cv::resize(img, img, rescaleSize, 0, 0, cv::INTER_LINEAR) ;
4.copyTo
cv::Rect roi;
roi.x = 0;
roi.y = 0;
roi.height = floor(img.rows / 2);
roi.width = floor(img.cols / 2);
cv::Mat crop_img;
img(roi).copyTo(crop_img);
关于Mat数据复制:前面说过Mat包括头和数据指针,当使用Mat的构造函数初始化的时候,会将头和数据指针复制(注意:只是指针复制,指针指向的地址不会复制),若要将数据也复制,则必须使用copyTo或clone函数
5.存储:按行存的
遍历图像
int h,w,c;
for (h=0; h<height; h++)
for (w=0; w<width; w++)
for(c=0; c<channel; c++)
top_index = (h*width+w)*channel+c; // 即:先channel, 再宽,再高
注:上述遍历自己没有亲自测试?
在输出uchar类型时,需先将其转化为整型(int)...
-----------------------------------------------
为了加快访问的速度,openCV往往会在内存中将像素数据连续地存储成一行,isContinus()函数的作用就是用于判断是否连续存储成一行。存储成一行有什么好处呢?给定这行的头指针p,则只要使用p++操作就能逐个访问数据。
因此当判断存放在一行的时候,可以通过数据指针++很容易遍历图像像素:
long nRows = M.rows * M.channels(); // channels()也是Mat中一个常用的函数,用于获取通道数(RGB=3,灰度=1)
long nCols = M.cols;
uchar *p = M.data; // 数据指针
if(M.isContinuous())
{
nCols *= nRows;
for (long i=0; i < nCols; i++) {
*p++ = ...; // 像素赋值或读取操作
}
}
请注意以上几个常用的Mat成员遍历和函数:
M.row; // 返回图像行数
M.nCols; // 返回图像列数
M.channels(); //返回通道数
M.isContinuous(); // 返回bool类型表示是否连续存储
部分摘自
http://docs.opencv.org/2.4/doc/tutorials/core/how_to_scan_images/how_to_scan_images.html?highlight=accessing%2520element
http://xiahouzuoxin.github.io/notes/html/OpenCV%E5%9F%BA%E7%A1%80%E7%AF%87%E4%B9%8BMat%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84.html
扩展阅读