基于opencv和c++的图像处理:直方图匹配
在冈萨雷斯的那本《数字图像处理》中提到了一种神奇的变换:直方图匹配变换(Histogram Matching), 输入两幅图A和B,A和B的直方图不同,直方图匹配变换是这样的一个变换s = F(r), 使得变换之后,A的直方图和B的直方图一样。也就是它们的颜色分布变成一样。
比如下面两幅图:
一个沙漠,一个海滩,它们的RGB直方图显然是不一样的。
但是执行直方图匹配变换后,沙漠那张图就变成这样了
和海滩那张图的直方图比一下,会发现上图的直方图与之几乎是一样的。沙漠图也就带上了海滩的味道。 这个变换的神奇之处在于,假设海滩那种图中的每个像素点都是可以自由移动的,在经过某次神奇的移动之后,海滩变成了沙漠,但是他们视觉上的色彩效果是一致的,不同的是像素点在不同的位置所造成的结构上的差异。
细看之后,海滩化后的沙漠怎么还有一个地方是沙子的颜色呢?其实是海滩上的沙子移过来的。当然,这个变换其实是近似的,主要是因为其中用到了一个变换的反变换,而该变换并不是双射,所以其反变换是近似的,这个也是代码中比较复杂的地方。详细的算法细节可以参考冈萨雷斯的那本数字图像处理,当然最好是看英文版,那本中文版我是根本没看懂。
相关代码:
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<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;//加前哨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;}