3

I want to realize smth like tone curve.

I have predefined set of curves that I should apply to the image. For instance: enter image description here

as I understand on this chart we see dependences of current tone value to new, for example: if we get first dot on the left - every r,g and b that = 0 will be converted to 64 or every value more than 224 will be converted to 0 and ect.

so I tried to change every pixel of image to new value

for test purpose i've simplified curve:

enter image description here

and here the code I have:

//init original image
cv::Mat originalMat = [self cvMatFromUIImage:inputImage];

//out image the same size
cv::Mat outMat      = [self cvMatFromUIImage:inputImage];

//loop throw every row of image
for( int y = 0; y < originalMat.rows; y++ ){
    //loop throw every column of image
   for( int x = 0; x < originalMat.cols; x++ ){
     //loop throw every color channel of image (R,G,B)
     for( int c = 0; c < 3; c++ ){

        if(originalMat.at<cv::Vec3b>(y,x)[c] <= 64)
       outMat.at<cv::Vec3b>(y,x)[c] = 64 + ( originalMat.at<cv::Vec3b>(y,x)[c] ) -
        ( originalMat.at<cv::Vec3b>(y,x)[c] ) * 2    ;

        if((originalMat.at<cv::Vec3b>(y,x)[c] > 64)&&(originalMat.at<cv::Vec3b>(y,x)[c] <= 128))
        outMat.at<cv::Vec3b>(y,x)[c] = (( originalMat.at<cv::Vec3b>(y,x)[c] ) - 64  ) * 4
        ;

        if((originalMat.at<cv::Vec3b>(y,x)[c] > 128))
        outMat.at<cv::Vec3b>(y,x)[c] = ( originalMat.at<cv::Vec3b>(y,x)[c] ) + 128 -
        (( originalMat.at<cv::Vec3b>(y,x)[c] ) - 128)  * 3;

     } //end of r,g,b loop
   } //end of column loop
 } //end of row loop

//send to output
return [self UIImageFromCVMat:outMat];

but here the result I get: enter image description here

by some reason only 3/4 of image was processed

and it not matches with result i expected: enter image description here

Update 0

thanks to @ACCurrent comment found errors in calculation(code and image updated), but still not understand why only 3/4 of images processed.

not sure that understand why 'noise' appears, hope it because of curve not smooth.

looks the way to avoid .at operation.

Update 1

original image:

enter image description here

Siarhei
  • 2,358
  • 3
  • 27
  • 63
  • 1
    Avoid using the opencv `.at<>` function it is very slow. Also on first inspection lets assume the value at `gaussMat.at(y,x)[c]` = 128 Then: `if((gaussMat.at(y,x)[c] > 64)&&(gaussMat.at(y,x)[c] <= 128)) outMat.at(y,x)[c] = ( gaussMat.at(y,x)[c] ) - 64 + ( gaussMat.at(y,x)[c] ) * 4` So 128-64+128*4 is equal to 576, way beyond 255 the max value for CV_U8c. So there will be a lot of saturation. – ACCurrent Feb 08 '17 at 00:43
  • 1
    Can you post the original image also? And don't worry... the `at` function is not slow. You can use it without any problem. – Miki Feb 08 '17 at 08:56
  • @Miki original image added – Siarhei Feb 08 '17 at 09:33
  • In the code you posted there are problems with the `{`, `}` in the for loops. Please correct them, and check that the result still bad. Also, please `cout << originalMat.type();` – Miki Feb 08 '17 at 09:54
  • @Miki sorry, missed `{` when edited code. thanks. updated question. the problem still here. `originalMat.type()` is equals to 24 – Siarhei Feb 08 '17 at 10:17

1 Answers1

3

You need to access the images with Vec4b


originalMat.type() is equals to 24

Your originalMat is of type 24, i.e. CV_8UC4. This means that the image has 4 channels, but you're accessing it with Vec3b as if it has only 3 channels. This explains why about 1/4 of the image is not modified.

So, simply replace every Vec3b in your code with Vec4b.

Miki
  • 40,887
  • 13
  • 123
  • 202