图中红点的坐标是(2,1) 还是 (1,2)答案是(2,1)!为什么? 看清了 我问的是坐标!!不是行列!!
那么(2,1) 和 (1,2)究竟有什么不同?
(2,1)表示的是红点的坐标,就是红点的 x 坐标是 2, y 坐标是 1。
(1,2)表示的是红点的行和列,就是红点的行是1,列是2,也就是红点在第 1 行,第 2 列。
这下子我相信大家都明白这两者的区别了吧!
//---------------------------------【头文件、命名空间包含部分】---------------------------
// 描述:包含程序所使用的头文件和命名空间
//-----------------------------------------------------------------------------------------------
#include "opencv2/core/core.hpp"
#include
using namespace std;
using namespace cv;
//--------------------------------------【main( )函数】-----------------------------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main(int,char**){
Mat I = Mat::eye(4, 4, CV_64F);
I.at<double>(1,1) = CV_PI;
cout << "\nI\n" << I << endl;
Mat r = Mat(5, 3, CV_8UC3);
randu(r, Scalar::all(0), Scalar::all(255));
cout << "r\n" << r << endl << endl;
Point2f p(6, 2);
cout << "【2维点】p = " << p << ";\n" << endl;
Point3f p3f(8, 2, 0);
cout << "【3维点】p3f = " << p3f << ";\n" << endl;
vector<float> v;
v.push_back(3);
v.push_back(5);
v.push_back(7);
cout << "【基于Mat的vector】shortvec = \n" << Mat(v) << ";\n"<<endl;
vector<Point2f> points(10);
for (size_t i = 0; i < points.size(); ++i)
points[i] = Point2f((float)(i * 5), (float)(i % 7));
cout << "【二维点向量】points = \n" << points<<";";
return 0;
}
下面说一下如何显示像素
srcImage.at(j, i)
srcImage.at(Point(j, i))
opencv灰度图mat.at
显示不出来会乱码,如果你也是单通道灰度图的话,和我一样的情况的话,记得转成int(mat.at
指针法读写像素
读写一个灰度图像GRAY像素点的像素值Scalar intensity = Mat.at
读写一个RGB彩色像素点的像素值
浮点型:
float blue = srcImage.at<Vec3b>(row, col)[0]; //获得蓝色通道b 的像素值
float green = srcImage.at<Vec3b>(row, col)[1]; //获得绿色通道g的像素值
float red = srcImage.at<Vec3b>(row, col)[2]; //获得红色通道r的像素值
整型:
int blue = srcImage.at<Vec3b>(row, col)[0]; //获得蓝色通道b 的像素值
int green = srcImage.at<Vec3b>(row, col)[1]; //获得绿色通道g的像素值
int red = srcImage.at<Vec3b>(row, col)[2]; //获得红色通道r的像素值
单通道(灰度图)
int ROWS = 100; // height
int COLS = 200; // width
Mat img1(ROWS , COLS , CV_32FC1);
for (int i=0; i<ROWS ; i++)
{
for (int j=0; j<COLS ; j++)
{
img1.at<float>(i,j) = 3.2f;
}
}
type的类型具体要看Mat对象的通道数据类型:
Mat_<uchar>---------CV_8U
Mat<char>-----------CV_8S
Nat_<short>---------CV_16S
Mat_<ushort>--------CV_16U
Mat_<int>-----------CV_32S
Mat_<float>----------CV_32F
Mat_<double>--------CV_64F
三通道(彩色图)
int ROWS = 100; // height
int COLS = 200; // width
Mat img1(ROWS , COLS , CV_8UC3);
for (int i=0; i<ROWS ; i++)
{
for (int j=0; j<COLS ; j++)
{
img1.at<vec3b>(i,j)[0]= 3.2f; // B 通道
img1.at<vec3b>(i,j)[1]= 3.2f; // G 通道
img1.at<vec3b>(i,j)[2]= 3.2f; // R 通道
}
}
RGB3通道图像Mat转uchar及uchar转Mat,编程环境:opencv2.4.13 ,
由于OpenCV读入和显示都是BGR类型,本文显示图像也用的BGR格式,若需换成RGB,程序中有对应替换程序。
先说一下要用到的Vec3b类型:
对于彩色图像中的一行,每列中有3个uchar元素,这可以被认为是一个小的包含uchar元素的vector,在OpenCV中用 Vec3b 来命名。
//Vec---是一个OpenCv的---向量类模板(向量模板类)
//Vec---向量类模板的类模板原型:
template<typename _Tp, int cn> class Vec : public Matx<_Tp, cn, 1>
//实例化:
typedef Vec<uchar, 3> Vec3b;
//Vec3b---表示每一个Vec3b对象中,可以存储3个char(字符型)数据,比如可以用这样的对象,去存储RGB图像中的一个像素点
//Vec3b使用:
//描述一种RGB颜色:
Vec3b color;
color[0]=0;//B分量
color[1]=0;//G分量
color[2]=255;//R分量
#include
using namespace std;
using namespace cv;
/**将Mat类型的数据转换为uchar类型*/
uchar* matToUchar(Mat img)
{
int img_width = img.cols;
int img_height = img.rows;
uchar *p1=(uchar*)malloc(sizeof(uchar)*img_height*img_width*3);/*[img_width * img_height * 3]*/
for (int i = 0; i < img_width * img_height * 3; i++)
{
p1[i] = (uchar)img.at<Vec3b>(i / (img_width * 3), (i % (img_width * 3)) / 3)[i % 3];
}
return p1;
}
/**将uchar类型的数据转换为Mat类型*/
int ucharToMat(uchar *p2,Mat& src,int flag)
{
int img_width = src.cols;
int img_height = src.rows;
//Mat img(Size(img_width, img_height), CV_8UC3);
for (int i = 0; i < img_width * img_height * 3; i++)
{
src.at<Vec3b>(i / (img_width * 3), (i % (img_width * 3)) / 3)[i % 3] = p2[i];//BGR格式
//src.at(i / (img_width * 3), (i % (img_width * 3)) / 3)[i % 3] = p2[i];//换为RGB使用
}
flag = 1;
return flag;
}
int main()
{
Mat img = imread("01.jpg", 1);
uchar* img_p = matToUchar(img);
int img_height = img.rows;
int img_width = img.cols;
Mat view(img_height, img_width, CV_8UC3, Scalar(0, 0, 0));
int flag_ucharTomat = ucharToMat(img_p, view, 0);
if (flag_ucharTomat)
{
printf("图片格式转换成功!");
}
cvNamedWindow("Image view", 0);
imshow("Image view", view);
cvWaitKey(0);
cvDestroyWindow("Image view");
}
cmake_minimum_required(VERSION 2.8)
project(imageBasics)
set(CMAKE_BUILD_TYPE "Debug")
# 添加c++ 11标准支持
set(CMAKE_CXX_FLAGS "-std=c++11 -O2")
# 寻找OpenCV库
find_package(OpenCV REQUIRED)
add_executable(a_basis a_basis.cpp)
target_link_libraries(a_basis ${OpenCV_LIBS})
#include
#include
#include
#include
#include
int main(int argc, char **argv) {
// 本教程通过创建二维三通道图像,创建带alpha通道的透明图像和读取图像来讲解图像的维度,通道,深度,类型,四种遍历方式等相关内容
/*****************************************************************************
* 创建一张二维三通道图像
*****************************************************************************/
cv::Mat q_image(674, 1200, CV_8UC3, cv::Scalar(0,0,255));
/**
* cv::Mat定义一个矩阵行数/高为image.rows,列数/宽为image.cols
* CV_(位数)+(数据类型)+(通道数)
* 其中CV_后面紧接的数字表示位数,分别对应8bit,16bit
* U表示Unsigned无符号整数类型,即其内部元素的值不可以为负数
* S表示Signed有符号整数类型,其值存在负数
* F则表示浮点数类型,即矩阵的内部元素值可以为小数(32对应单精度float类型,64对应双精度double类型)
* C1~C4表示对应的通道数,即有1~4个通道
*
*【1】CV_8UC1---可以创建---8位无符号的单通道---灰度图片---grayImg
* #define CV_8UC1 CV_MAKETYPE(CV_8U,1) type 预定义的常量 = 0
*
*【2】CV_8UC3---可以创建---8位无符号的三通道---RGB彩色图像---colorImg
* #define CV_8UC3 CV_MAKETYPE(CV_8U,3) type 预定义的常量 = 16
*
*【3】CV_8UC4---可以创建---8位无符号的四通道---带透明色Alpha通道的RGB图像
* #define CV_8UC4 CV_MAKETYPE(CV_8U,4) type 预定义的常量 = 24
*
* cv::Scalar(0,0,255)每个像素由三个元素组成即三通道,初始化颜色值为(0,0,255)
*
*/
std::cout << "q_image.rows: " << q_image.rows << std::endl; // 674
std::cout << "q_image.cols: " << q_image.cols << std::endl; // 1200
std::cout << "q_image.dims: " << q_image.dims << std::endl; // 2
std::cout << "q_image.channels(): " << q_image.channels() << std::endl; // 3
std::cout << "q_image.type(): " << q_image.type() << std::endl; // 16
/**
* 类型表示了矩阵中元素的类型以及矩阵的通道个数
* 它是一系列的预定义的常量,其命名规则为CV_(位数)+(数据类型)+(通道数)
* CV_8UC3 = 16 , CV_16UC3 = 18
*/
std::cout << "q_image.depth(): " << q_image.depth() << std::endl; // 0
// depth用来度量每一个像素中每一个通道的精度,但它本身与图像的通道数无关,depth数值越大精度越高
// Opencv中,Mat.depth()得到的是一个0~6的数字,分别代表不同的位数
// 对应关系如下: enum{CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6}
// 可见0和1都代表8位,2和3都代表16位,4和5代表32位,6代表64位
// 其中U是unsigned无符号数的意思,S表示signed有符号数的意思
std::cout << "q_image.elemSize(): " << q_image.elemSize() << std::endl; // 3(通道)
// 矩阵中元素的个数为image.rows*image.cols=674*1200
// elemSize以8位(一个字节)为单位表示矩阵中每一个元素的字节数
// 数据类型是CV_8UC1,elemSize==1
// 数据类型是CV_8UC3或CV_8SC3,elemSize==3
// 数据类型是CV_16UC3或CV_16SC3,elemSize==6
std::cout << "q_image.elemSize1(): " << q_image.elemSize1() << std::endl; // 1(字节)
// elemSize加上一个"1"构成了elemSize1这个属性,可认为是元素内1个通道的意思
// 表示Mat矩阵中每一个元素单个通道的数据大小,以字节为单位,所以eleSize1==elemSize/channels
std::cout << "q_image.step: " << q_image.step << std::endl; // 3600
// step可以理解为Mat矩阵中每一行的"步长",以字节为单位,step=elemSize()*cols=3*1200=3600
// 每一行中所有元素的字节总量,累计了一行中所有元素,所有通道,所有通道的elemSize1之后的值
cv::namedWindow( "q_image", CV_WINDOW_AUTOSIZE );
imshow( "q_image", q_image);
cv::waitKey(0);
/*****************************************************************************
* 创建一张alpha通道的Mat图像
*****************************************************************************/
cv::Mat mat(480, 640, CV_8UC4);//创建带alpha通道的Mat
for(int i = 0; i < mat.rows; ++i) {
for(int j = 0; j < mat.cols; ++j) {
auto &rgba = mat.at<cv::Vec4b>(i, j);
/**
* OpenCV源代码中的定义 typedef Vec Vec2b
* Vec2b 表示每个Vec2b对象可以存储2个char(字符型)数据
* vec3b 表示每个Vec3b对象可以存储3个char(字符型)数据,比如可以用这样的对象,去存储RGB图像中的
* vec4b 表示每个Vec4b对象可以存储4个字符型数据,可以用这样的类对象去存储—4通道RGB+Alpha的图
* mat.at(i, j);
* 从mat中取出一个像素,像素的类型是Vec4b该类型含义是,有4个UCHAR类型的元素
* 其中rgba[0],rgba[1],rgba[2]代表像素三原色BGR,即为蓝色Blue,Green绿色,红色Red,rgba[3]代表像素的Alpha值表示像素透明度
*/
rgba[0]= UCHAR_MAX;
rgba[1]= cv::saturate_cast<uchar>((float (mat.cols - j)) / ((float)mat.cols) *UCHAR_MAX);
rgba[2]= cv::saturate_cast<uchar>((float (mat.rows - i)) / ((float)mat.rows) *UCHAR_MAX);
rgba[3]= cv::saturate_cast<uchar>(0.5 * (rgba[1] + rgba[2]));
}
}
imshow("带alpha通道的图像",mat);
cv::waitKey(0);
/*****************************************************************************
* 读取一张二维三通道图像
*****************************************************************************/
cv::Mat image;
image = cv::imread("../ubuntu.png", -1);// 新版本OpenCV中引入Mat类自动管理内存处理图像数据 读入一张图片
/**
* CV_LOAD_IMAGE_UNCHANGED = flag = -1 8位深度 原通道 按照图像原样读取 保留Alpha通道(第4通道)
* CV_LOAD_IMAGE_GRAYSCALE = flag = 0 8位深度 1通道 将图像转成单通道灰度图像后读取
* CV_LOAD_IMAGE_COLOR = flag = 1 8位深度 3通道 将图像转换成3通道BGR彩色图像
*/
if (image.data == nullptr) {
std::cerr << "文件不存在." << std::endl;// 判断图像文件是否正确读取如果不能读取可能是文件不存在
return 0;// 没有读取图片return 0终止函数
}
cv::namedWindow( "image", CV_WINDOW_AUTOSIZE );// OpenCV创建显示图像窗口"image"
imshow( "image", image);// 在窗口"image"显示图像image
cv::waitKey(0);// 等待任意按键按下退出,不加这一句窗口会一闪而过,等待6000 ms后窗口自动关闭 waitKey(6000);
std::cout << "image.rows: " << image.rows << std::endl;// image.rows图像的行数是: 674 是高度
std::cout << "image.cols: " << image.cols << std::endl;// image.cols图像的列数是: 1200 是宽度 1200*674
std::cout << "image.dims: " << image.dims << std::endl;// image.dims图像的维度是: 2
std::cout << "image.channels(): " << image.channels() << std::endl;// image.channels()图像的通道是: 3
std::cout << "image.type(): " << image.type() << std::endl;// image.type()图像的类型是: 16
std::cout << "image.depth(): " << image.depth() << std::endl;// image.depth()图像的深度是: 0
std::cout << "image.elemSize(): " << image.elemSize() << std::endl;// image.elemSize()图像的elemSize是: 3
std::cout << "image.elemSize1(): " << image.elemSize1() << std::endl;// image.elemSize1()图像的elemSize1是: 1
cv::Mat gray_image;
cv::cvtColor(image, gray_image, cv::COLOR_BGR2GRAY);// 转换为灰度图像
imshow( "gray_image", gray_image);// 在窗口"gray_image"显示图像gray_image
cv::waitKey(0);// 按任意键退出,不加这一句窗口会一闪而过
std::cout << "gray_image.rows: " << gray_image.rows << std::endl;// gray_image.rows图像的行数是: 674
std::cout << "gray_image.cols: " << gray_image.cols << std::endl;// gray_image.cols图像的列数是: 1200
std::cout << "gray_image.dims: " << gray_image.dims << std::endl;// gray_image.dims图像的维度是: 2
std::cout << "gray_image.channels(): " << gray_image.channels() << std::endl;// gray_image.channels()图像的通道是: 1
std::cout << "gray_image.type(): " << gray_image.type() << std::endl;// gray_image.type()图像的类型是: 0
std::cout << "gray_image.depth(): " << gray_image.depth() << std::endl;// gray_image.depth()图像的深度是: 0
std::cout << "gray_image.elemSize(): " << gray_image.elemSize() << std::endl;// gray_image.elemSize()图像的elemSize是: 1
std::cout << "gray_image.elemSize1(): " << gray_image.elemSize1() << std::endl;// gray_image.elemSize1()图像的elemSize1是: 1
/*****************************************************************************
* 常用Mat类矩阵元素读取方式有:通过at方法进行读取,通过指针ptr进行读取,通过迭代器进行读取,
* 通过矩阵元素的地址定位方式进行读取,接下来将详细的介绍这四种读取方式.
*****************************************************************************/
// 通过at方法读取单通道Mat矩阵类中的元素
cv::Mat M4 = (cv::Mat_<double>(3, 3) << 0, -1, 0, -1, 0, 0, 0, 0, 1);
// 创建自定义数据的矩阵Mat
std::cout << "M4 = " << std::endl << M4 << std::endl;
double value = M4.at<double>(0,1); // -1
// 通过at方法读取元素需要在后面跟上<数据类型>以坐标的形式给出需要读取的元素坐标(行数,列数)
std::cout << "value = " << value << std::endl;
// at 方法读取三通道Mat矩阵类中的元素
/**
* Mat类中获取或改变该像素点的灰度值或者RGB值,可以通过image.at(i,j)的方式。
* 单通道图像image.at(i, j) i对应的是点的y坐标,j对应的是点的x坐标,而不是我们习惯的(x,y)
* RGB
* image.at(i, j)[0]
* image.at(i, j)[1]
* image.at(i, j)[2]
*/
cv::Mat M5(3, 4, CV_8UC3, cv::Scalar(0, 0, 255));
// 读取彩色图像像素
for(int i = 0;i < M5.rows;i++){
for(int j = 0;j < M5.cols;j++){
std::cout << "M5.at(i,j)[0]: " << int(M5.at<cv::Vec3b>(i,j)[0]) << std::endl; //蓝色通道
std::cout << "M5.at(i,j)[0]: " << int(M5.at<cv::Vec3b>(i,j)[1]) << std::endl; //绿色通道
std::cout << "M5.at(i,j)[0]: " << int(M5.at<cv::Vec3b>(i,j)[2]) << std::endl; //红是通道
// 通过at方法读取多通道Mat矩阵类中的元素,多通道矩阵每一个元素坐标处都是多个数据,因此引入一个变量用于表示同一元素多个数据
// OpenCV中定义cv::Vec3b,cv::Vec3s,cv::Vec3w,cv::Vec3d,cv::Vec3f,cv::Vec3i六种类型表示同一个元素的三个通道数据
// 数字表示通道的个数,最后一位是数据类型的缩写,b是uchar类型的缩写,s是short类型的缩写,w是ushort类型的缩写,
// d是double类型的缩写,f是float类型的缩写,i是int类型的缩写
}
}
// 通过指针ptr读取Mat类矩阵中的元素
cv::Mat M6(3, 4, CV_8UC3, cv::Scalar(0, 0, 1));
for (int i = 0; i < M6.rows; i++){
// 循环遍历图像的每一行
uchar* row_ptr = M5.ptr(i);
// 用cv::Mat::ptr获得图像的行头指针,再定义一个uchar类型的row_ptr指向第i行的头指针
for (int j = 0; j < M6.cols*M6.channels(); j++){
// 循环遍历图像矩阵中每一行所有通道的数据
// Mat类矩阵矩阵中每一行中的每个元素都是挨着存放,每一行中存储的数据数量为列数与通道数的乘积
// 即代码中指针向后移动cols*channels()-1位,当读取第2行数据中第3个数据时,可以直接用M6.ptr(1)[2]访问
std::cout << "row_ptr[" << j << "]: " << (int)row_ptr[j] << std::endl;
// 循环输出每一个通道中的数值
}
}
// 通过迭代器访问Mat类矩阵中的元素
// Mat类变量同时也是一个容器变量,所以Mat类变量拥有迭代器,用于访问Mat类变量中的数据,通过迭代器可以实现对矩阵中每一个元素的遍历
cv::Mat M7(3, 4, CV_8UC3, cv::Scalar(0, 1, 2));
cv::MatIterator_<uchar> it = M7.begin<uchar>();
// 初始位置的迭代器
cv::MatIterator_<uchar> it_end = M7.end<uchar>();
// 终止位置的迭代器
// Mat类的迭代器变量类型是cv::MatIterator_< >,在定义时同样需要在括号中声明数据的变量类型
// Mat类迭代器的起始是Mat.begin< >(),结束是Mat.end< >(),与其他迭代器用法相同,通过"++"运算实现指针位置向下迭代
// 数据的读取方式是先读取第一个元素的每一个通道,之后再读取第二个元素的每一个通道,直到最后一个元素的最后一个通道
for(; it != it_end; it++){
std::cout << (int)(*it) << " ";
std::cout << std::endl;
}
cv::destroyAllWindows();
return 0;
}
#include
#include
using namespace std;
using namespace cv;
void colorReduce(Mat& inputImage, Mat& outputImage, int div);
int main( )
{
Mat srcImage = imread("../11.jpg");
imshow("11",srcImage);
Mat dstImage;
dstImage.create(srcImage.rows,srcImage.cols,srcImage.type());
colorReduce(srcImage,dstImage,32);
imshow("22",dstImage);
imwrite("../dstImage.png",dstImage);
waitKey(0);
}
void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{
outputImage = inputImage.clone();
int rowNumber = outputImage.rows;
int colNumber = outputImage.cols*outputImage.channels();
for(int i = 0;i < rowNumber;i++)
{
uchar* data = outputImage.ptr<uchar>(i);
for(int j = 0;j < colNumber;j++)
{
data[j] = data[j]/div*div + div/2;
}
}
}
#include //头文件
#include
#include
using namespace cv; //包含cv命名空间
void createAlphaMat(Mat &mat)
{
for(int i = 0; i < mat.rows; ++i) {
for(int j = 0; j < mat.cols; ++j) {
Vec4b&rgba = mat.at<Vec4b>(i, j);
rgba[0]= UCHAR_MAX;
rgba[1]= saturate_cast<uchar>((float (mat.cols - j)) / ((float)mat.cols) *UCHAR_MAX);
rgba[2]= saturate_cast<uchar>((float (mat.rows - i)) / ((float)mat.rows) *UCHAR_MAX);
rgba[3]= saturate_cast<uchar>(0.5 * (rgba[1] + rgba[2]));
}
}
}
int main( )
{
// 【1】读入一张图片,载入图像
Mat srcImage = imread("../1.jpg");
// 【2】显示载入的图片
imshow("【原始图】",srcImage);
//进行腐蚀操作
Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));
Mat dstImage;
erode(srcImage, dstImage, element);
//显示效果图
imshow("【效果图】腐蚀操作", dstImage);
imwrite("../腐蚀.png",dstImage);
//【3】进行均值滤波操作
blur( srcImage, dstImage, Size(7, 7));
//【4】显示效果图
imshow( "均值滤波【效果图】" ,dstImage );
imwrite("../模糊.png",dstImage);
Mat edge,grayImage; //参数定义
//【1】创建与src同类型和大小的矩阵(dst)
dstImage.create( srcImage.size(), srcImage.type() );
//【2】将原图像转换为灰度图像
cvtColor( srcImage, grayImage, COLOR_BGR2GRAY );
//【3】先用使用 3x3内核来降噪
blur( grayImage, edge, Size(3,3) );
//【4】运行Canny算子
Canny( edge, edge, 3, 9,3 );
//【5】显示效果图
imshow("【效果图】Canny边缘检测", edge);
imwrite("../边缘检测.png", edge);
//创建带alpha通道的Mat
Mat mat(480, 640, CV_8UC4);
createAlphaMat(mat);
imwrite("../透明Alpha值图.png", mat);
imshow("生成的png图",mat);
// 【3】等待任意按键按下
// waitKey(0);
// 【3】等待6000 ms后窗口自动关闭
waitKey(1000);
return 0;
}