In the Book Digital Image Processing in Gonzalez, a magical transformation is mentioned: Histogram Matching, which inputs two images A and B, different from the histogram of A and B, the Histogram Matching transformation is such a transformation S = f (R), so that after the transformation, the histogram of A is the same as that of B. That is, their color distribution becomes the same.
For example, the following two images:
A desert, a beach, and their RGB histograms are obviously different.
However, after performing Histogram Matching and transformation, the desert chart becomes like this.
Compared with the histogram of the beach chart, we will find that the histogram is almost the same. The desert map also brings the taste of the beach. The magic of this change is that, assuming that every pixel in the beach graph can be moved freely, after a magical movement, the beach becomes a desert, however, their visual color effects are the same. The difference is the difference in the structure of pixels at different locations.
After looking at it, how can there be another place in the desert after the beach is turned into the sand color? In fact, the sand on the beach is moved. Of course, this transformation is actually an approximation, mainly because an inverse transformation of the transformation is used, and this transformation is not a dual-shot, so its inverse transformation is an approximation, this is also a complicated part of the code. For detailed algorithm details, please refer to the digital image processing book of Gonzalez. Of course, it is best to read the English version. I didn't understand the Chinese version at all.
Related code:
Bool gfimage: histogrammatching (const gfimage & anoimage) {assert (getchannel () = anoimage. getchannel (); // R-> svector <vector <uchar> vrsmap; calculatemapfunbyhiseq (vrsmap); // Z-> svector <vector <uchar> vzsmap; anoimage. calculatemapfunbyhiseq (vzsmap); vector <uchar> vrzmap; vrzmap. resize (getchannel (); For (int ch = 0; ch <getchannel (); ch ++) {vrzmap [CH]. resize (256) ;}for (int ch = 0; ch <getchannel (); Ch ++) {vector <int> vszmap; vszmap. resize (256); For (INT I = 0; I <256; I ++) {vszmap [I] =-1 ;}for (INT z = 255; z> = 0; Z --) {vszmap [vzsmap [CH] [Z] = z;} vector <int> vsindex; // Add an slice vsindex. push_back (-1); For (int s = 0; S <256; s ++) {If (vszmap [s]! =-1) {vsindex. push_back (s) ;}/// vsindex. push_back( 256); For (INT I = 0; I <vsindex. size ()-1; I ++) {int startidx = vsindex [I] + 1; int endidx = vsindex [I + 1]-1; int loweridx = vsindex [I]; int upperidx = vsindex [I + 1]; if (I = 0) {loweridx = upperidx;} if (I = vsindex. size ()-2) {upperidx = loweridx;} int nlen = endidx-startidx + 1; int nmididx = startidx + nlen/2; for (Int J = startidx; j <nmididx; j ++) {vszmap [J] = vszmap [loweridx];} For (Int J = nmididx; j <= endidx; j ++) {vszmap [J] = vszmap [upperidx] ;}}for (INT r = 0; r <256; r ++) {vrzmap [CH] [r] = vszmap [vrsmap [CH] [r] ;}}for (int ch = 0; ch <getchannel (); ch ++) {uchar * pdata = getdata (); For (INT r = 0; r <getheight (); R ++) {uchar * pline = pdata + R * getwidthstep (); for (int c = 0; C <getwidth (); C ++) {uchar val = pline [getchannel () * C + CH]; pline [getchannel () * C + CH] = vrzmap [CH] [Val] ;}} return true ;}
Complete code can be found here