Ask Your Question
0

Why does my own implementation of color conversion differ from cv::cvtColor() ?

asked 2017-04-03 06:43:58 -0600

f4f gravatar image

Hi. I have implemented a little function to convert CV_8UC3 (bgr) to CV_8UC1 grayscale using formula provided with cv::cvtColor() docs : GRAY = 0.114 * B + 0.587f *G + 0.299f * R

Though output of my func is quite similar to one of cv::cvtColor(BGR2Gray), when checking each pixel's value in loop discovers lots of bad pixels. What is wrong ?

My function is below:

void bgr2gray(cv::Mat& src, cv::Mat& dst) { CV_Assert(!src.empty());

int width = src.cols;
int height = src.rows;
int channels = src.channels();

CV_Assert(src.channels() == 3 && dst.channels() == 1);
CV_Assert(width == dst.cols && height == dst.rows);
CV_Assert(src.isContinuous() && dst.isContinuous());


// src.isContinious() && dst.isContinious()
width *= height;
height = 1;

uchar* p_src;
uchar* p_dst;

for (int i = 0; i < height; i++) {
    p_src = src.ptr<uchar>(i);
    p_dst = dst.ptr<uchar>(i);
    for (int j = 0; j < width * channels; j += 3) {
        float d_gray(0.114F * p_src[j] + 0.587f * p_src[j + 1] + 0.299f * p_src[j + 2]);
        uchar gray = (uchar)d_gray;

        if (gray - d_gray >= 0.5f)
            gray += 1;

        p_dst[j / 3] = gray;
    }
  }
    }
edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
2

answered 2017-04-03 08:43:54 -0600

LBerger gravatar image

updated 2017-04-03 08:48:20 -0600

One of source code in opencv is here.

Now in your question if you add an example with real value it would be easier to understand where the problem could be

p_src = src.ptr<uchar>(i); with a 3 channels it is weird src.ptr<vec3b>(i) is better and saturate_cast is better than if ( ..>0.5

edit flag offensive delete link more

Comments

src.ptr<uchar>(i) is the fastest way to iterate through cv::Mat and it is also suggested in tutorials.

f4f gravatar imagef4f ( 2017-04-04 01:41:22 -0600 )edit
1

I have added cv::staurate_cast<uchar> as you pointed and it fixed the problem. So now loop's body is following;

uchar* p_src;
uchar* p_dst;

for (int i = 0; i < height; i++) {
    p_src = src.ptr<uchar>(i);
    p_dst = dst.ptr<uchar>(i);
    for (int j = 0; j < width * channels; j += 3) {
        uchar gray = cv::saturate_cast<uchar>(0.114f * p_src[j] + 0.587f * p_src[j + 1] + 0.299f * p_src[j + 2]);

        p_dst[j / 3] = gray;
    }
}

Now it's time to cast a glance at source code of saturate_cast. Thanks a lot.

f4f gravatar imagef4f ( 2017-04-04 01:48:22 -0600 )edit

saturate_cast it's here and faster way is to parallelize your code using ParallelLoopBody

LBerger gravatar imageLBerger ( 2017-04-04 02:24:20 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2017-04-03 06:43:58 -0600

Seen: 514 times

Last updated: Apr 03 '17