c++ - 图像像素值未在 CV::Mat 中更新(OpenCV 4.1.2;C++)

标签 c++ opencv

我正在尝试实现 Floyd-Steinberg dithering algorithm (在带有 MSVC 2015 c++ 编译器的 Qt Creator 上使用 OpenCV 4.1.2)。

我在尝试更新 cv::Mat 对象值时遇到问题,但我无法这样做。虽然我找到了解决它的方法,但我仍然不明白为什么 Mat img 在函数 dithering [line: 90] 中获胜不会更改,但如果使用注释 [line: 105] 而不是 [line: 104],代码将起作用。

我的问题是: 为什么会这样?是不是因为 cv::Mat 以某种方式传递了指针或缩小后的彩色图像的地址?或者只是一些 OpenCV 魔法?

图像和结果: Original Image Reduced Image Result Image(No Error) Result Image(With Error)

    1. #include <vector>
    2. #include <sstream>
    3. #include <iostream>
    4. 
    5. #include <opencv2/core.hpp>
    6. #include <opencv2/opencv.hpp>
    7. #include <opencv2/highgui.hpp>
    8. #include <opencv2/imgcodecs.hpp>
    9. #include <opencv2/core/matx.hpp>
    10.#include <opencv2/core/utility.hpp>
    11. 
    12. 
    13. using namespace std;
    14. using namespace cv;
    15. 
    16. 
    17. Mat init(int argc, char *argv[]);
    18. Mat reduceVal(Mat src);
    19. uchar reduceVal(uchar);
    20. Mat dithering(Mat src);
    21. uchar addError(uchar pixel, int error, float numerator, float denominator);
    22. 
    23. 
    24. int main(int argc, char *argv[])
    25. {
    26.     Mat image = init(argc, argv);
    27.     if (image.empty()) {
    28.         cout << "Wrong argumnets or no image data\n";
    29.         return -1;
    30.     }
    31. 
    32.     namedWindow("Colored Image", WINDOW_AUTOSIZE);
    33.     imshow("Colored Image", image);
    34. 
    35.     Mat reducedImage(image.rows, image.cols, image.type());
    36.     reducedImage = reduceVal(image.clone());
    37.     namedWindow("Reduced Value Image", WINDOW_AUTOSIZE);
    38.     imshow("Reduced Value Image", reducedImage);
    39. 
    40.     Mat ditheredImage(image.rows, image.cols, image.type());
    41.     ditheredImage = dithering(image.clone());
    42.     namedWindow("Dithert Image", WINDOW_AUTOSIZE);
    43.     imshow("Dithert Image", ditheredImage);
    44. 
    45.     imwrite("reducedImage.png", reducedImage);
    46.     imwrite("floyedSteinberg_image.png", ditheredImage);
    47.     waitKey(0);
    48.     return 0;
    49. }
    50. 
    51. Mat init(int argc, char *argv[])
    52. {
    53.     if (argc < 2) {
    54.         cout << "Huston we have a problem" << endl;
    55.         return Mat();
    56.     }
    57.     string imageName = argv[1];
    58.     Mat image = imread(imageName, IMREAD_COLOR);
    59.     return image;
    60. }
    61. 
    62. Mat reduceVal(Mat img)
    63. {
    64.     int rows = img.rows;
    65.     img = img.reshape(0, 1);
    66.     for (int i = 0; i < img.cols; i++) {
    67.         for (int k = 0; k < 3; k++) {
    68.             uchar colorVal = img.at<Vec3b>(i)[k];
    69.             if (colorVal < (255 - 51)) {
    70.                 colorVal = uchar(colorVal / 51 + 0.5) * 51;
    71.             } else {
    72.                 colorVal = 255;
    73.             }
    74.             img.at<Vec3b>(i)[k] = colorVal;
    75.         }
    76.     }
    77.     return img.reshape(0, rows).clone();
    78. }
    79. 
    80. uchar reduceVal(uchar colorVal)
    81. {
    82.     if (colorVal < (255 - 51)) {
    83.         return uchar(colorVal / 51 + 0.5) * 51;
    84.     } else {
    85.         return 255;
    86.     }
    87. }
    88. 
    89. 
    90. Mat dithering(Mat img)
    91. {
    92.     uchar oldPixel, newPixel;
    93.     int quantError;
    94.     Mat imageNew(img.rows, img.cols, img.type());
    95.     imageNew = reduceVal(img.clone());
    96.     imshow("dithering begin ", img);
    97.     imshow("Reduced Image", imageNew);
    98.     for (int r = 0; r < img.rows - 1; r++) {
    99.         for (int c = 1; c < img.cols - 1; c++) {
    100.            Point anchor(c, r);
    101.            for (int k = 0; k < img.channels(); k++) {
    102.                Point pt = anchor;
    103.                oldPixel = img.at<Vec3b>(pt)[k];
    104.                newPixel = imageNew.at<Vec3b>(pt)[k];
    105. //             newPixel = reduceVal(oldPixel);
    106.                img.at<Vec3b>(pt)[k] = newPixel;
    107.                quantError = oldPixel - newPixel;
    108.                pt = Point(anchor.x + 1, anchor.y);
    109.        img.at<Vec3b>(pt)[k] = addError(img.at<Vec3b>(pt)[k], quantError, 7.0f, 16.0f);
    110.                pt = Point(anchor.x - 1, anchor.y + 1);
    111.        img.at<Vec3b>(pt)[k] = addError(img.at<Vec3b>(pt)[k], quantError, 3.0f, 16.0f);
    112.                pt = Point(anchor.x, anchor.y + 1);
    113.        img.at<Vec3b>(pt)[k] = addError(img.at<Vec3b>(pt)[k], quantError, 5.0f, 16.0f);
    114.                pt = Point(anchor.x + 1, anchor.y + 1);
    115.        img.at<Vec3b>(pt)[k] = addError(img.at<Vec3b>(pt)[k], quantError, 1.0f, 16.0f);
    116.            }
    117.        }
    118.    }
    119.    return img;
    120. }
    121. 
    122. uchar addError(uchar pixel, int error, float numerator, float denominator)
    123. {
    124.    int sum = pixel + static_cast<int>(error * (numerator / denominator));
    125.    if (sum > 255) {// making sure that 'sum' belongs to [0,255]
    126.        return uchar(255);
    127.    } else if (sum < 0) {
    128.        return 0;
    129.    } else {
    130.        return uchar(sum);
    131.    }
    132. }

最佳答案

您的代码在循环的每次迭代中修改 img 的数据。我的意思是当你处理 (x,y), 像素(x+1,y),(x-1,y+1),( x,y+1)(x+1,y+1)被改变并存储在img中。所以 在下一次迭代中,您使用上一步的修改值计算新值(这是使用的情况 newPixel = reduceVal(oldPixel);)

  -------->          
  |
  |      C x   you iterate from top to bottom, from left to right 
  |    x x x   so error value is propagated with next iterations 
 \ /

上述情况不会发生

newPixel = imageNew.at<Vec3b>(pt)[k];

因为您正在读取未使用 addError 调用计算的像素值 - 这些值不受邻居值的影响。

关于c++ - 图像像素值未在 CV::Mat 中更新(OpenCV 4.1.2;C++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59311078/

相关文章:

c++ - 如何删除和删除指向存储在 vector 中的对象的指针?

opencv - 手势识别 OpenCV(用于媒体播放器)

python - 使用适用于python的OpenCV捕获网络摄像头可获取白屏

c++ - std::vector 以外的排名保持数据结构?

c++ - 通过套接字从 Linux 向 Windows 机器发送空字节 - 会相同吗

python-3.x - 人脸识别系统如何区分真实人脸和人脸照片?

opencv - 如何使用opencv 2.1.0版本从前景中去除阴影

image - 使用 DLib 提取感兴趣区域

c++ - 哪个更快 : x<<1 or x<<10?

c++ - 画线算法