I came across an extremely simple color balancing algorithm here. And I thought I’ll quickly transcode it to OpenCV.
Here’s the gist:
Tag: color
Sharing a bit of code I created for skin detection.
Hi!
I’ve been working on implementing a face image relighting algorithm using spherical harmonics, one of the most elegant methods I’ve seen lately.
I start up by aligning a face model with OpenGL to automatically get the canonical face normals, which brushed up my knowledge of GLSL. Then I continue to estimating real faces “spharmonics”, and relighting.
Let’s start!
Hi,
I’ll present a quick and simple implementation of image recoloring, in fact more like color transfer between images, using OpenCV in C++ environment. The basis of the algorithm is learning the source color distribution with a GMM using EM, and then applying changes to the target color distribution. It’s fairly easy to implement with OpenCV, as all the “tools” are built in.
I was inspired by Lior Shapira’s work that was presented in Eurographics 09 about image appearance manipulation, and a work about recoloring for the colorblind by Huang et al presented at ICASSP 09. Both works deal with color manipulation using Gaussian Mixture Models.
Update 5/28/2015: Adrien contributed code that works with OpenCV v3! Thanks! https://gist.github.com/adriweb/815c1ac34a0929292db7
Let’s see how it’s done!
This is a tutorial on using Graph-Cuts and Gaussian-Mixture-Models for image segmentation with OpenCV in C++ environment.
Update 10/30/2017: See a new implementation of this method using OpenCV-Python, PyMaxflow, SLIC superpixels, Delaunay and other tricks.
Been wokring on my masters thesis for a while now, and the path of my work came across image segmentation. Naturally I became interested in Max-Flow Graph Cuts algorithms, being the “hottest fish in the fish-market” right now if the fish market was the image segmentation scene.
So I went looking for a CPP implementation of graphcut, only to find out that OpenCV already implemented it in v2.0 as part of their GrabCut impl. But I wanted to explore a bit, so I found this implementation by Olga Vexler, which is build upon Kolmogorov’s framework for max-flow algorithms. I was also inspired by Shai Bagon’s usage example of this implementation for Matlab.
Let’s jump in…
Hi
I wanted to do the simplest recoloring/color-transfer I could find – and the internet is just a bust. Nothing free, good and usable available online… So I implemented the simplest color transfer algorithm in the wolrd – Histogram Matching.
Here’s the implementation with OpenCV
Justin Talbot has done a tremendous job implementing the GrabCut algorithm in C [link to paper, link to code]. I was missing though, the option to load ANY kind of file, not just PPMs and PGMs.
So I tweaked the code a bit to receive a filename and determine how to load it: use the internal P[P|G]M loaders, or offload the work to the OpenCV image loaders that take in many more type. If the OpenCV method is used, the IplImage is converted to the internal GrabCut code representation.
Image<Color>* load( std::string file_name ) { if( file_name.find( ".pgm" ) != std::string::npos ) { return loadFromPGM( file_name ); } else if( file_name.find( ".ppm" ) != std::string::npos ) { return loadFromPPM( file_name ); } else { return loadOpenCV(file_name); } } void fromImageMaskToIplImage(const Image<Real>* image, IplImage* ipli) { for(int x=0;x<image->width();x++) { for(int y=0;y<image->height();y++) { //Color c = (*image)(x,y); Real r = (*image)(x,y); CvScalar s = cvScalarAll(0); if(r == 0.0) { s.val[0] = 255.0; } cvSet2D(ipli,ipli->height - y - 1,x,s); } } } Image<Color>* loadIplImage(IplImage* im) { Image<Color>* image = new Image<Color>(im->width, im->height); for(int x=0;x<im->width;x++) { for(int y=0;y<im->height;y++) { CvScalar v = cvGet2D(im,im->height-y-1,x); Real R, G, B; R = (Real)((unsigned char)v.val[2])/255.0f; G = (Real)((unsigned char)v.val[1])/255.0f; B = (Real)((unsigned char)v.val[0])/255.0f; (*image)(x,y) = Color(R,G,B); } } return image; } Image<Color>* loadOpenCV(std::string file_name) { IplImage* im = cvLoadImage(file_name.c_str(),1); Image<Color>* i = loadIplImage(im); cvReleaseImage(&im); return i; }
Well, there’s nothing fancy here, but it does give you a fully working GrabCut implementation on top of OpenCV… so there’s the contribution.
GrabCutNS::Image<GrabCutNS::Color>* imageGC = GrabCutNS::loadIplImage(orig); GrabCutNS::Image<GrabCutNS::Color>* maskGC = GrabCutNS::loadIplImage(mask); GrabCutNS::GrabCut *grabCut = new GrabCutNS::GrabCut( imageGC ); grabCut->initializeWithMask(maskGC); grabCut->fitGMMs(); //grabCut->refineOnce(); grabCut->refine(); IplImage* __GCtmp = cvCreateImage(cvSize(orig->width,orig->height),8,1); GrabCutNS::fromImageMaskToIplImage(grabCut->getAlphaImage(),__GCtmp); //cvShowImage("result",image); cvShowImage("tmp",__GCtmp); cvWaitKey(30);
I also added the GrabCutNS namespace, to differentiate the Image class from the rest of the code (that probably has an Image already).
Code is as usual available online in the SVN repo.
Enjoy!
Roy.