经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
OpenCV操作像素
来源:cnblogs  作者:小佬頭  时间:2018/11/5 10:54:01  对本文有异议

在了解了图像的基础知识和OpenCV的基础知识和操作以后,接下来我们要做的就对像素进行操作,我们知道了图像的本质就是一个矩阵,那么一个矩阵中存储了那么多的像素,我们如何来操作呢?下面通过几个例子来看看像素的操作。

这个是原图,接下来的例子都是对这个图片进行操作的。

访问像素出现雪花效果

我们需要有雪花的效果,这里的雪花其实就是一个个白色的点,白色在像素值是255,所以我们的思路就是在一个图像上面的矩阵中的一些像素值转成值为255的,如果是彩色的图像的话就是三个通道,那么就是分别对三个通道的值都转为255,三通道在OpenCV里面是按照蓝绿红的顺序排布的。

  • 代码实现
  1. #include <opencv2/core/core.hpp>
  2. #include <opencv2/highgui/highgui.hpp>
  3. #include <opencv2/imgproc/imgproc.hpp>
  4. #include <random>
  5. // Add white noise to an image
  6. void white(cv::Mat image, int n) {
  7. // C++11 random number generator
  8. std::default_random_engine generator;
  9. std::uniform_int_distribution<int> randomRow(0, image.rows - 1);
  10. std::uniform_int_distribution<int> randomCol(0, image.cols - 1);
  11. int i,j;
  12. for (int k=0; k<n; k++) {
  13. // 生成图形位置
  14. i= randomCol(generator);
  15. j= randomRow(generator);
  16. if (image.type() == CV_8UC1) { //灰度图像
  17. // 单通道8位
  18. image.at<uchar>(j,i)= 255;
  19. } else if (image.type() == CV_8UC3) { // color image
  20. // 3通道,分别是蓝绿红
  21. image.at<cv::Vec3b>(j,i)[0]= 255;
  22. image.at<cv::Vec3b>(j,i)[1]= 255;
  23. image.at<cv::Vec3b>(j,i)[2]= 255;
  24. // or simply:
  25. // image.at<cv::Vec3b>(j, i) = cv::Vec3b(255, 255, 255);
  26. }
  27. }
  28. }
  29. int main()
  30. {
  31. // open the image
  32. cv::Mat image= cv::imread("boldt.jpg",1);
  33. // call function to add noise
  34. white(image,3000);
  35. // display result
  36. cv::namedWindow("Image1");
  37. cv::imshow("Image1",image);
  38. // write on disk
  39. cv::imwrite("salted.bmp",image);
  40. cv::waitKey();
  41. // test second version
  42. cv::Mat image2= cv::imread("boldt.jpg",0);//0表示灰度图
  43. white(image2, 500);
  44. cv::namedWindow("Image2");
  45. cv::imshow("Image2",image2);
  46. cv::waitKey();
  47. return 0;
  48. }
  • 效果

指针遍历像素:减少图像中颜色的数量

彩色图像由三通道像素组成,每个通道表示红、绿、蓝三原色中一种颜色的亮度值,每个数值都是8位无符号字符类型,因此颜色总数为 256×256×256,即超过 1600 万种颜色。

所以有时候为了降低分析的复杂性,需要减少图像中颜色的数量。

一种实现方法是把RGB空间细分到大小相等的方块中。例如,如果把每种颜色数量减少到 1/8,那么颜色总数就变为 32×32×32。将旧图像中的每个颜色值划分到一个方块,该方块的中间值就是新的颜色值;新图像使用新的颜色值,颜色数就减少了。

所以在这里的减少图像中颜色的数量的思路的步骤是:

  • 假设 N 是减色因子,将图像中每个像素的值除以 N(这里假 定使用整数除法,不保留余数)。

  • 然后将结果乘以 N,得到 N 的倍数,并且刚好不超过原始像素 值。

  • 加上 N / 2,就得到相邻的 N 倍数之间的中间值。

  • 对所有 8 位通道值重复这个过程,就会得到 (256 / N) × (256 / N) × (256 / N)种可能的颜色值。

  1. #include <iostream>
  2. #include <opencv2/core/core.hpp>
  3. #include <opencv2/highgui/highgui.hpp>
  4. void reduceColor(cv::Mat image, int div = 64)
  5. {
  6. int nl = image.rows;//行数
  7. int nc = image.cols * image.channels();//每一行的像素数量
  8. for (int i = 0; i < nl; ++i) {
  9. //获取行i的地址
  10. auto data = image.ptr<uchar>(i);
  11. for (int j = 0; j < nc; ++j) {
  12. //处理每一个像素
  13. data[j] = data[j]/div*div + div/2;
  14. }
  15. }
  16. }
  17. int main()
  18. {
  19. cv::Mat image = cv::imread("boldt.jpg");
  20. reduceColor(image, 64);
  21. cv::namedWindow("image");
  22. cv::imshow("image", image);
  23. cv::waitKey();
  24. return 0;
  25. }
  • 效果图

当然刚刚的这个代码是用普通的遍历完成的,我们也可以用迭代器完成对像素的遍历

  1. void reduceColorNew(cv::Mat image, int div=64) {
  2. // div must be a power of 2
  3. int n= static_cast<int>(log(static_cast<double>(div))/log(2.0) + 0.5);
  4. // mask used to round the pixel value
  5. uchar mask= 0xFF<<n; // e.g. for div=16, mask= 0xF0
  6. uchar div2 = div >> 1; // div2 = div/2
  7. // get iterators
  8. cv::Mat_<cv::Vec3b>::iterator it= image.begin<cv::Vec3b>();
  9. cv::Mat_<cv::Vec3b>::iterator itend= image.end<cv::Vec3b>();
  10. // scan all pixels
  11. for ( ; it!= itend; ++it) {
  12. // process each pixel ---------------------
  13. (*it)[0]&= mask;
  14. (*it)[0]+= div2;
  15. (*it)[1]&= mask;
  16. (*it)[1]+= div2;
  17. (*it)[2]&= mask;
  18. (*it)[2]+= div2;
  19. // end of pixel processing ----------------
  20. }
  21. }

扫描图像并访问相邻像素

在图像处理中经常有这样的处理函数,它在计算每个像素的数值时,需要使用周边像素的值。 如果相邻像素在上一行或下一行,就需要同时扫描图像的多行。

我们将使用一个锐化图像的处理函数。它基于拉普拉斯算子。在图像处理领域有一个众所周知的结论:如果从图像中减去拉普拉斯算子部分,图像 的边缘就会放大,因而图像会变得更加尖锐。

实现思路:

  • 图像扫描中使用了三个指针
  • 一个表 示当前行、一个表示上面的行、一个表示下面的行
  • 另外,因为在计算每一个像素时都需要访问 与它相邻的像素,所以有些像素的值是无法计算的,比如第一行、最后一行和第一列、最后一列 的像素。
  1. #include <iostream>
  2. #include <opencv2/core/core.hpp>
  3. #include <opencv2/highgui/highgui.hpp>
  4. #include <opencv2/imgproc/imgproc.hpp>
  5. void sharpen(const cv::Mat &image, cv::Mat &result) {
  6. result.create(image.size(), image.type()); // allocate if necessary
  7. int nchannels= image.channels();
  8. for (int j= 1; j<image.rows-1; j++) { // for all rows (except first and last)
  9. const uchar* previous= image.ptr<const uchar>(j-1); // previous row
  10. const uchar* current= image.ptr<const uchar>(j); // current row
  11. const uchar* next= image.ptr<const uchar>(j+1); // next row
  12. uchar* output= result.ptr<uchar>(j); // output row
  13. for (int i=nchannels; i<(image.cols-1)*nchannels; i++) {
  14. // apply sharpening operator
  15. *output++= cv::saturate_cast<uchar>(5*current[i]-current[i-nchannels]-current[i+nchannels]-previous[i]-next[i]);
  16. }
  17. }
  18. // Set the unprocess pixels to 0
  19. result.row(0).setTo(cv::Scalar(0));
  20. result.row(result.rows-1).setTo(cv::Scalar(0));
  21. result.col(0).setTo(cv::Scalar(0));
  22. result.col(result.cols-1).setTo(cv::Scalar(0));
  23. }
  24. int main()
  25. {
  26. cv::Mat image= cv::imread("boldt.jpg");
  27. if (!image.data)
  28. return 0;
  29. cv::Mat result;
  30. double time= static_cast<double>(cv::getTickCount());
  31. sharpen(image, result);
  32. time= (static_cast<double>(cv::getTickCount())-time)/cv::getTickFrequency();
  33. std::cout << "time= " << time << std::endl;
  34. cv::namedWindow("Image");
  35. cv::imshow("Image",result);
  36. cv::waitKey();
  37. return 0;
  38. }

时间:time= 0.00339625

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号