Ask Your Question
2

How to map colors

asked 2015-03-12 10:45:53 -0600

501 Not Implemented gravatar image

updated 2015-03-12 14:58:43 -0600

Hello, I want to map some colors in a image to another color the colors are available as HSV (8UC3).

For example:

mapping all pixels with H= 90, S= 128, V = 128 to H= 70, S= 128, V = 128
mapping all pixels with H= 100, S= 128, V = 128 to H= 110, S= 128, V = 128
and so on...

I know about:

  • cv::InRange: very slow, if I have a big map
  • cv::LUT: allows only 256 colors?

has someone an idea or a solution for this problem?

For a first approach it suffice to get a mask of all these colors.

EDIT

one idea: iterate the image, and create a map from all colors associated by pixels (color[H,S,V] -> vector of (X,Y)- Coordinate) after that I can iterate the colors I want to change and set all pixel of the vector to the new color. This solution is very slow, I think but maybe much faster as cv::inrange ? (for maybe 5,000 colors) What do you think?

EDIT 2

I've tested my idea on a i5 with a color wheel image (2400 x 2400 pixels) in RGB - space image description

In this test I save the pointers to the pixel in a map (vector of iterators associated by a color id) After that, I iterate all colors in the map (65453 colors) and set the inverted color to each pixel of the vector This solution needs round about 2,5 seconds (I meassured with getTickCount()) and after some optimazion I run it with 1 second. Faster than a concatination of cv::inrange

Maybe someone has another solution, that is faster than this?

best regards

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
0

answered 2015-03-12 12:00:20 -0600

thdrksdfthmn gravatar image

I have tried to change one color to another, so I have created a class that has these functions:

cv::Mat SolColorChanger::changeColor(const cv::Mat& hsvImageIn)
{
    MatVector hsvChannels;
    cv::split(hsvImageIn, hsvChannels);

    cv::Mat msk;
    cv::bitwise_xor(hsvChannels[0] > m_oldColor - m_deltaColor, hsvChannels[0] < m_oldColor + m_deltaColor, msk);
    cv::bitwise_not(msk,  msk);
    cv::morphologyEx(msk, msk, cv::MORPH_CLOSE, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 5)));
    Displayer::displayImage(msk, "color mask", DISPLAY);
    hsvChannels[0].setTo(m_newColor, msk);

    cv::Mat edited;
    cv::merge(hsvChannels, edited);
    cv::cvtColor(edited, edited, cv::COLOR_HSV2BGR);

    return edited;
}

void SolColorChanger::execute()
{
    cv::Mat hsv;
    cv::cvtColor(m_image2edit, hsv, cv::COLOR_BGR2HSV);
    Displayer::displayImage(m_image2edit, "input image", DISPLAY);
    Displayer::displayImage(hsv, "hsv image", DISPLAY);

    cv::Mat colored = changeColor(hsv);
    Displayer::displayImage(colored, "edited", DISPLAY);

    IO::saveImage(colored, m_savingName);
}

The m_oldColor is the color to be changed (red, blue, orange, etc. it has a H value); m_newColor is the new H value and the m_deltaColor is the error of hue value. I have not tested on huge images and in a loop to see its performances, so let me now how fast is it, if you test it.

edit flag offensive delete link more

Comments

Hi, to do this with every color produce a lot of overhead. But thanks for your solution :) for a little count of colors this works fine at least because there not iterate the whole image. Actually that is for 8*-bit images, see the docs for better understanding, but LUT should be fast

501 Not Implemented gravatar image501 Not Implemented ( 2015-03-12 14:59:58 -0600 )edit

Other way to do it, I think that a LUT on hue channel, will be fast. In OpenCV hue from HSV has the values between [0, 179], so it will be fast

thdrksdfthmn gravatar imagethdrksdfthmn ( 2015-03-13 03:01:20 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2015-03-12 10:45:53 -0600

Seen: 2,150 times

Last updated: Mar 12 '15