【opencv学习之十六】像素操作和Reduce Color的例子
程序员文章站
2022-06-01 08:45:51
...
访问像素的方法很多这里举三个经典例子,第一个是椒盐噪声,就是在图像上随机将其中的某些像素至为白色,看起来就像撒了盐;
代码如下:
////1.访问像素并修改
void salt()
{
Mat image;
int n=10000;
image = cv::imread("D:/2.jpg");
int i, j;
for (int k = 0; k < n; k++) {
i = std::rand() % image.cols;//c++rand()函数生成随机整数,最大值image.cols;
j = std::rand() % image.rows;//c++rand()函数生成随机整数,最大值image.cols;
if (image.type() == CV_8UC1) // CV_8UC1为灰度图像
{
image.at<uchar>(j, i) = 255;//这个方法是将这个点变为白色;at方法为一个模板函数,调用时候指定元素类型,uchar为0-255;
}
else if (image.type() == CV_8UC3) // CV_8UC3为彩色图像(三通道)
{
// Vec3b---表示每一个Vec3b对象中,可以存储3个char(字符型)数据,比如可以用这样的对象,去存储RGB图像中的一个像素点
//Opencv中图像三原色在内存中的排列顺序为B-G-R
image.at<cv::Vec3b>(j, i)[0] = 255;//访问第一通道B
image.at<cv::Vec3b>(j, i)[1] = 255;//访问第二通道G
image.at<cv::Vec3b>(j, i)[2] = 255;//访问第三通道R
}
}
cv::imshow("Image", image);
cv::waitKey(0);
}
效果如下:
下面是集中减少色彩的操作,比如原来的图像是是256中颜色,我希望将它变成64种颜色,那我只需要将原来的颜色除以4(整除)以后再乘以4就可以了;
1、直接访问at操作:
void colorReduce1()//mat,at操作方法,直接访问像素点
{
Mat image;
image = cv::imread("D:/2.jpg");
int div = 64;
int rows = image.rows;
int cols = image.cols;
for(int i = 0;i < rows;i++)
{
for(int j = 0;j < cols;j++)
{
image.at<Vec3b>(i,j)[0] = image.at<Vec3b>(i,j)[0]/div*div + div/2;
image.at<Vec3b>(i,j)[1] = image.at<Vec3b>(i,j)[1]/div*div + div/2;
image.at<Vec3b>(i,j)[2] = image.at<Vec3b>(i,j)[2]/div*div + div/2;
}
}
cv::imshow("Image", image);
cv::waitKey(0);
}
2、逐行操作:
//逐行读取
/// 经典的Reduce Color的例子,即对图像中的像素表达进行量化。
/// 如常见的RGB24图像有256×256×256中颜色,
/// 通过Reduce Color将每个通道的像素减少8倍至256/8=32种,
/// 则图像只有32×32×32种颜色。假设量化减少的倍数是N,
/// 则代码实现时就是简单的value/N*N,通常我们会再加上N/2以得到相邻的N的倍数的中间值,
/// 最后图像被量化为(256/N)×(256/N)×(256/N)种颜色。
void colorReduce2()
{
Mat image;
image = cv::imread("D:/2.jpg");
int div = 64;
int nl = image.rows; // 行数
int nc = image.cols * image.channels(); // 每行的元素数量
for (int j = 0; j < nl; j++)//遍历行数
{
uchar* data = image.ptr<uchar>(j);//cv::Mat类提供ptr函数,可以直接访问图像中任一行的地址
for (int i = 0; i < nc; i++)//遍历一行的元素
{
data[i] = data[i] / div*div + div / 2; //修改像素值
//*data = *data / div*div + div2; data++; //另一种等价的做法, 即利用指针运算从一列移到下一列
}
}
cv::imshow("Image", image);
cv::waitKey(0);
}
3、容器操作:
//mat操作,容器操作
void colorReduce3()
{
Mat image;
image = cv::imread("D:/2.jpg");
int div = 64;
cv::Mat_<cv::Vec3b>::iterator it;//模板子类,因此迭代器返回cv::Vec3b实例
it = image.begin<cv::Vec3b>();//begin起始位
cv::Mat_<cv::Vec3b>::iterator itend =image.end<cv::Vec3b>();// end结束位置
for (; it != itend; ++it)
{
(*it)[0] = (*it)[0] / div*div + div / 2;//用[ ]访问每个颜色通道的元素,返回cv::Vec3b
(*it)[1] = (*it)[1] / div*div + div / 2;
(*it)[2] = (*it)[2] / div*div + div / 2;
}
cv::imshow("Image", image);
cv::waitKey(0);
}
//指针方法
void colorReduce4()
{
Mat image;
image = cv::imread("D:/2.jpg");
int div = 64;
int rows = image.rows;
int cols = image.cols*image.channels();
for(int i = 0;i < rows;i++)
{
uchar* data = image.ptr<uchar>(i);
uchar* dataout =image.ptr<uchar>(i);
for(int j = 0;j < cols;j++)
{
dataout[j] = dataout[j]/div*div + div/2;
}
}
cv::imshow("Image", image);
cv::waitKey(0);
}
所有操作效果图一样,如下:原图如下: