簡體   English   中英

CV::Mat (OpenCV 4.1.2; C++) 中不更新圖像像素值

[英]Image pixel values are not updated in CV::Mat (OpenCV 4.1.2; C++)

我正在嘗試實現Floyd-Steinberg 抖動算法(在帶有 MSVC 2015 c++ 編譯器的 Qt Creator 上使用 OpenCV 4.1.2)。

當我嘗試更新cv::Mat對象值時遇到了一個問題,但我無法這樣做。 雖然我找到了解決它的方法,但我仍然不明白為什么函數dithering Mat img [ line: 90 ] 不會改變,但是如果使用注釋的 [ line: 105 ] 而不是 [ line: 104 ] ] 代碼有效。

我的問題是:為什么會這樣? 是因為不知何故cv::Mat傳遞了指針或減少的彩色圖像的地址? 或者只是一些 OpenCV 魔法?

圖像和結果:原始圖像縮小圖像結果圖像(無錯誤)結果圖像(有錯誤)

    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調用計算的像素值 - 這些值不受鄰居值的影響。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM