# How to map colors

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...


• 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

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 close merge delete

Sort by ยป oldest newest most voted

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)));
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.

more

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

( 2015-03-12 14:59:58 -0500 )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

( 2015-03-13 03:01:20 -0500 )edit

Official site

GitHub

Wiki

Documentation