Bayer图像不做赘述
一、Bayer(GRBG)图像转RGB
处理方法:对于某个像素点,存在的分量值不变化,缺少的两个分量值使用Correlation-Adjusted算法
QImage CorrelationAdjusted(QImage srcImg, int type) { int imgW = srcImg.width(); int imgH = srcImg.height(); // if (srcImg.format() != QImage::Format_Grayscale8) // return srcImg; if (type == 0) return srcImg; QImage dstImg(imgW, imgH, QImage::Format_Grayscale8); QImage colImg(imgW, imgH, QImage::Format_RGB888); uchar *srcImgData;// = srcImg.bits(); uchar *dstImgData;// = dstImg.bits(); uchar *colImgData;// = colImg.bits(); uchar r, g, b, temVal; for (int i = 0; i < imgH; i++) { dstImgData = dstImg.scanLine(i); colImgData = colImg.scanLine(i); srcImgData = srcImg.scanLine(i); //判断边缘两行 if (i < 2 || i >= imgH - 2) { int Raver, Rtot, Gaver, Gtot, Baver, Btot; for (int j = 0; j < imgW; j++) { Raver = Rtot = Gaver = Gtot = Baver = Btot = 0; if (i % 2 == j % 2) { if (i > 0) { if (i % 2) Raver += srcImg.scanLine(i - 1)[j], Rtot++; else Baver += srcImg.scanLine(i - 1)[j], Btot++; } if (i < imgH - 1) { if (i % 2) Raver += srcImg.scanLine(i + 1)[j], Rtot++; else Baver += srcImg.scanLine(i + 1)[j], Btot++; } if (j > 0) { if (i % 2) Baver += srcImgData[j - 1], Btot++; else Raver += srcImgData[j - 1], Rtot++; } if (j < imgW - 1) { if (i % 2) Baver += srcImgData[j + 1], Btot++; else Raver += srcImgData[j + 1], Rtot++; } Gaver = srcImgData[j], Gtot = 1; } else { if (i > 0) Gaver += srcImg.scanLine(i - 1)[j], Gtot++; if (i < imgH - 1) Gaver += srcImg.scanLine(i + 1)[j], Gtot++; if (j > 0) Gaver += srcImgData[j - 1], Gtot++; if (j < imgW - 1) Gaver += srcImgData[j + 1], Gtot++; int Naver = 0, Ntot = 0; if (i > 0) { if (j > 0) Naver += srcImg.scanLine(i - 1)[j - 1], Ntot++; if (j < imgW - 1) Naver += srcImg.scanLine(i - 1)[j + 1], Ntot++; } if (i < imgH - 1) { if (j > 0) Naver += srcImg.scanLine(i + 1)[j - 1], Ntot++; if (j < imgW - 1) Naver += srcImg.scanLine(i + 1)[j + 1], Ntot++; } if (i % 2) { Baver = srcImgData[j], Btot = 1; Raver = Naver, Rtot = Ntot; } else { Raver = srcImgData[j], Rtot = 1; Baver = Naver, Btot = Ntot; } } colImgData[j * 3] = Raver / Rtot; colImgData[j * 3 + 1] = Gaver / Gtot; colImgData[j * 3 + 2] = Baver / Btot; } continue; } uchar *aboveLine2 = srcImg.scanLine(i - 2); uchar *aboveLine1 = srcImg.scanLine(i - 1); uchar *belowLine1 = srcImg.scanLine(i + 1); uchar *belowLine2 = srcImg.scanLine(i + 2); for (int j = 0; j < imgW; j++) { /*边缘两列*/ if (j < 2 || j >= imgW - 2) { int Raver, Rtot, Gaver, Gtot, Baver, Btot; Raver = Rtot = Gaver = Gtot = Baver = Btot = 0; if (i % 2 == j % 2) { if (i % 2) { Raver += aboveLine1[j], Rtot++; Raver += belowLine1[j], Rtot++; } else { Baver += aboveLine1[j], Btot++; Baver += belowLine1[j], Btot++; } if (j > 0) { if (i % 2) Baver += srcImgData[j - 1], Btot++; else Raver += srcImgData[j - 1], Rtot++; } if (j < imgW - 1) { if (i % 2) Baver += srcImgData[j + 1], Btot++; else Raver += srcImgData[j + 1], Rtot++; } Gaver = srcImgData[j], Gtot = 1; } else { Gaver += aboveLine1[j], Gtot++; Gaver += belowLine1[j], Gtot++; if (j > 0) Gaver += srcImgData[j - 1], Gtot++; if (j < imgW - 1) Gaver += srcImgData[j + 1], Gtot++; int Naver = 0, Ntot = 0; if (j > 0) { Naver += aboveLine1[j - 1], Ntot++; Naver += belowLine1[j - 1], Ntot++; } if (i < imgH - 1) { Naver += belowLine1[j + 1], Ntot++; Naver += aboveLine1[j + 1], Ntot++; } if (i % 2) { Baver = srcImgData[j], Btot = 1; Raver = Naver, Rtot = Ntot; } else { Raver = srcImgData[j], Rtot = 1; Baver = Naver, Btot = Ntot; } } r = (uchar)(Raver / Rtot); g = (uchar)(Gaver / Gtot); b = (uchar)(Baver / Btot); } /*普通行列*/ else { if (i % 2 == j % 2) { r = i % 2 ? (aboveLine1[j] + belowLine1[j]) / 2 : (srcImgData[j - 1] + srcImgData[j + 1]) / 2; g = srcImgData[j]; b = i % 2 ? (srcImgData[j - 1] + srcImgData[j + 1]) / 2 : (aboveLine1[j] + belowLine1[j]) / 2; } else { r = i % 2 ? (aboveLine1[j - 1] + aboveLine1[j + 1] + belowLine1[j - 1] + belowLine1[j + 1]) / 4 : srcImgData[j]; short G1, G2, G3, G4, N1, N2, N3, N4; G1 = aboveLine1[j]; G2 = srcImgData[j + 1]; G3 = belowLine1[j]; G4 = srcImgData[j - 1]; N1 = aboveLine2[j]; N2 = srcImgData[j + 2]; N3 = belowLine2[j]; N4 = srcImgData[j - 2]; if (abs(N1 - N3) < abs(N2 - N4)) g = (G1 + G3) / 2; else if (abs(N1 - N3) > abs(N2 - N4)) g = (G3 + G4) / 2; else g = (G1 + G2 + G3 + G4) / 4; b = i % 2 ? srcImgData[j] : (aboveLine1[j - 1] + aboveLine1[j + 1] + belowLine1[j - 1] + belowLine1[j + 1]) / 4; } } if (type == 1) temVal = r; else if (type == 2) temVal = g; else if (type == 3) temVal = b; else if (type == 5) temVal = b - r > 0 ? b - r : r - b; else temVal = ((r + g) / 2 - b > 0) ? ((r + g) / 2 - b) : 0; colImgData[j * 3] = r; colImgData[j * 3 + 1] = g; colImgData[j * 3 + 2] = b; dstImgData[j] = temVal; } } if (type == 4) return colImg; return dstImg; }
二、白平衡处理,使用灰度世界GrayWorld方法
QImage ImageGrayWorld(QImage srcImg) { int imgW = srcImg.width(); int imgH = srcImg.height(); QImage dstImg(imgW, imgH, QImage::Format_RGB888); uchar *srcData;// = srcImg.bits(); uchar *dstData;// = dstImg.bits(); //计算R G B 三分量的平均灰度 double Raver = 0, Gaver = 0, Baver = 0; for (int i = 0; i < imgH; i++) { srcData = srcImg.scanLine(i); for (int j = 0; j < imgW; j++) { Raver += srcData[j * 3]; Gaver += srcData[j * 3 + 1]; Baver += srcData[j * 3 + 2]; } } Raver /= (imgW * imgH); Gaver /= (imgW * imgH); Baver /= (imgW * imgH); //计算各通道增益 double K = (Raver + Gaver + Baver) / 3; double Kr = K / Raver; double Kg = K / Gaver; double Kb = K / Baver; //重算RGB值 for (int i = 0; i < imgH; i++) { srcData = srcImg.scanLine(i); dstData = dstImg.scanLine(i); for (int j = 0; j < imgW; j++) { dstData[j * 3] = srcData[j * 3] * Kr > 255 ? 255 : srcData[j * 3] * Kr; dstData[j * 3 + 1] = srcData[j * 3 + 1] * Kg > 255 ? 255 : srcData[j * 3 + 1] * Kg; dstData[j * 3 + 2] = srcData[j * 3 + 2] * Kb > 255 ? 255 : srcData[j * 3 + 2] * Kb; } } return dstImg; }
三、白平衡处理,完美反射方法
QImage ImagePerfectReflector(QImage srcImg) { int imgH = srcImg.height(); int imgW = srcImg.width(); QImage dstImg(imgW, imgH, QImage::Format_RGB888); uchar *srcData; uchar *dstData; int Hist[255 * 3 + 10]; memset(Hist, 0, sizeof(Hist)); short **Sum = new short*[imgH]; for (int i = 0; i < imgH; i++) Sum[i] = new short[imgW]; //计算每个像素的R/G/B之和 short maxValue = 0; for (int i = 0; i < imgH; i++) { srcData = srcImg.scanLine(i); for (int j = 0; j < imgW; j++) { short sum = srcData[j * 3] + srcData[j * 3 + 1] + srcData[j * 3 + 2]; Hist[sum]++; Sum[i][j] = sum; if (maxValue < sum) maxValue = sum; } } //按照R+G+B值得大小计算出前10%或其他Ratio的白色参考值点的阈值T double Ratio = 8; double temSum = 0; short Threshold; for (short i = 765; i >= 0; i--) { temSum += Hist[i]; if (temSum > imgW * imgH * Ratio / 100) { Threshold = i; break; } } //遍历图像,计算R+G+B值大于Threshold的所有点的R/G/B分量的累积和的平均值 double Raver = 0, Gaver = 0, Baver = 0; int totAmount = 0; for (int i = 0; i < imgH; i++) { srcData = srcImg.scanLine(i); for (int j = 0; j < imgW; j++) { if (Sum[i][j] > Threshold) { Raver += srcData[j * 3]; Gaver += srcData[j * 3 + 1]; Baver += srcData[j * 3 + 2]; totAmount++; } } } Raver /= totAmount; Gaver /= totAmount; Baver /= totAmount; //对每个点将像素量化到[0,255]之间 short r, g, b; for (int i = 0; i < imgH; i++) { srcData = srcImg.scanLine(i); dstData = dstImg.scanLine(i); for (int j = 0; j < imgW; j++) { r = srcData[j * 3] * maxValue / Raver; g = srcData[j * 3 + 1] * maxValue / Gaver; b = srcData[j * 3 + 2] * maxValue / Baver; if (r > 255) r = 255; else if (r < 0) r = 0; if (g > 255) g = 255; else if (g < 0) g = 0; if (b > 255) b = 255; else if (b < 0) b = 0; dstData[j * 3] = r; dstData[j * 3 + 1] = g; dstData[j * 3 + 2] = b; } } for (int i = 0; i < imgH; i++) delete[] Sum[i]; delete[] Sum; return dstImg; }
4.白平衡处理,动态阈值方法
QImage ImageAutoWhiteBalance(QImage srcImg) { int imgH = srcImg.height(); int imgW = srcImg.width(); QImage dstImg = QImage(imgW, imgH, QImage::Format_RGB888); uchar *srcData; uchar *dstData; uchar **YCbCr = new uchar*[imgH]; for (int i = 0; i < imgH; i++) YCbCr[i] = new uchar[imgW * 3 + 10]; int Red, Green, Blue; int maxY = 0; //RGB 转 YCbCr 系数 int mul = 20; int semul = 1 << (mul - 1); int YiR = (int)( 0.299000f * (1 << mul) + 0.5); int YiG = (int)( 0.587000f * (1 << mul) + 0.5); int YiB = (int)( 0.114000f * (1 << mul) + 0.5); int CbR = (int)(-0.168736f * (1 << mul) + 0.5); int CbG = (int)(-0.331264f * (1 << mul) + 0.5); int CbB = (int)( 0.500000f * (1 << mul) + 0.5); int CrR = (int)( 0.500000f * (1 << mul) + 0.5); int CrG = (int)(-0.418688f * (1 << mul) + 0.5); int CrB = (int)(-0.081312f * (1 << mul) + 0.5); for (int i = 0; i < imgH; i++) { srcData = srcImg.scanLine(i); for (int j = 0; j < imgW; j++) { Red = srcData[j * 3]; Green = srcData[j * 3 + 1]; Blue = srcData[j * 3 + 2]; //Y, Cb, Cr YCbCr[i][j * 3] = (byte)((YiR * Red + YiG * Green + YiB * Blue + semul) >> mul); YCbCr[i][j * 3 + 1] = (byte)(128 + ((CbR * Red + CbG * Green + CbB * Blue + semul) >> mul)); YCbCr[i][j * 3 + 2] = (byte)(128 + ((CrR * Red + CrG * Green + CrB * Blue + semul) >> mul)); if (maxY < YCbCr[i][j * 3]) maxY = YCbCr[i][j * 3]; } } int deltW = imgW / 4; int deltH = imgH / 3; double Db[12], Dr[12]; double Mb[12], Mr[12]; short *HistY = new short[maxY + 1]; double *HistRGB = new double[3 * (maxY + 1)]; for (int i = 0; i < 3 * (maxY + 1); i++) HistRGB[i] = 0; for (int i = 0; i < maxY + 1; i++) HistY[i] = 0; int totWhite = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j < 4; j++) { Mb[i * 4 + j] = Mr[i * 4 + j] = 0; Db[i * 4 + j] = Dr[i * 4 + j] = 0; //计算每个区域Cb,Cr分量平均值Mb,Mr for (int r = i * deltH; r < (i + 1) * deltH; r++) { for (int c = j * deltW; c < (j + 1) * deltW; c++) { Mb[i * 4 + j] += YCbCr[r][c * 3 + 1]; Mr[i * 4 + j] += YCbCr[r][c * 3 + 2]; } } Mb[i * 4 + j] /= (deltW * deltH); Mr[i * 4 + j] /= (deltW * deltH); //计算每个区域Cb,Cr分量的绝对差的累积值Db,Dr for (int r = i * deltH; r < (i + 1) * deltH; r++) { for (int c = j * deltW; c < (j + 1) * deltW; c++) { Db[i * 4 + j] += abs(YCbCr[r][c * 3 + 1] - Mb[i * 4 + j]); Dr[i * 4 + j] += abs(YCbCr[r][c * 3 + 2] - Mr[i * 4 + j]); } } Db[i * 4 + j] /= (deltW * deltH); Dr[i * 4 + j] /= (deltW * deltH); //确定白色参考点 for (int r = i * deltH; r < (i + 1) * deltH; r++) { srcData = srcImg.scanLine(r); for (int c = j * deltW; c < (j + 1) * deltW; c++) { if (abs(YCbCr[r][c * 3 + 1] - (Mb[i * 4 + j] + Db[i * 4 + j] * abs(Mb[i * 4 + j]) / Mb[i * 4 + j])) < 1.5 * Db[i * 4 + j] && abs(YCbCr[r][c * 3 + 2] - (1.5 * Mr[i * 4 + j] + Dr[i * 4 + j] * abs(Mr[i * 4 + j]) / Mr[i * 4 + j]))) { int ValueY = (int)YCbCr[r][c * 3]; HistY[ValueY]++; totWhite++; HistRGB[ValueY * 3] += srcData[c * 3]; HistRGB[ValueY * 3 + 1] += srcData[c * 3 + 1]; HistRGB[ValueY * 3 + 2] += srcData[c * 3 + 2]; } } } } } int totNum = 0; //按大小取其亮度值10%的为最终确定的白色参考点,并计算R,G,B平均值 double Raver = 0, Gaver = 0, Baver = 0; for (int i = maxY; i >= 0; i--) { totNum += HistY[i]; Raver += HistRGB[i * 3]; Gaver += HistRGB[i * 3 + 1]; Baver += HistRGB[i * 3 + 2]; if (1.0 * totNum / totWhite >= 0.1) { Raver /= totNum; Gaver /= totNum; Baver /= totNum; break; } } //计算每个通道的增益 double Rgain = maxY / Raver; double Ggain = maxY / Gaver; double Bgain = maxY / Baver; //计算最终每个通道的分量值 for (int i = 0; i < imgH; i++) { srcData = srcImg.scanLine(i); dstData = dstImg.scanLine(i); for (int j = 0; j < imgW; j++) { dstData[j * 3] = Rgain*srcData[j * 3] > 255 ? 255 : Rgain*srcData[j * 3]; dstData[j * 3 + 1] = Ggain*srcData[j * 3 + 1] > 255 ? 255 : Ggain*srcData[j * 3 + 1]; dstData[j * 3 + 2] = Bgain*srcData[j * 3 + 2] > 255 ? 255 : Bgain*srcData[j * 3 + 2]; } } //内存释放 delete[] HistY; delete[] HistRGB; for (int i = 0; i < imgH; i++) delete[] YCbCr[i]; delete[] YCbCr; return dstImg; }