图像增强--视网膜皮层Retinex算法(二)
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                图像增强--视网膜皮层Retinex算法(二)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.                        
                                視網膜皮層Retinex算法可以參考下面兩篇文章
http://www.cnblogs.com/Imageshop/archive/2013/04/17/3026881.html
https://blog.csdn.net/carson2005/article/details/9502053
下面直接進行講解基于Opencv 4.10的Retinex算法實現
/*主函數*/ int main() {Mat orig;Mat dst;unsigned char * sImage, *dImage;int x, y;int nWidth, nHeight, step;orig = imread("test1.jpg", 1); /* 打開圖像 */nWidth = orig.cols;nHeight = orig.rows;step = orig.cols * orig.channels();dst.create(Size(nWidth, nHeight), CV_8UC3);/* 創建目標圖像 */sImage = (unsigned char*)malloc(sizeof(unsigned char)*(nHeight*nWidth * 3)); /* 創建2個圖像buffer */dImage = (unsigned char*)malloc(sizeof(unsigned char)*(nHeight*nWidth * 3));/* 創建2個顯示窗口,一個用于目標圖像,一個用于源圖像 */namedWindow("Original Image", WINDOW_AUTOSIZE);namedWindow("Result Image", WINDOW_AUTOSIZE);/* 取圖像進行處理 */imshow("Original Image", orig);for (y = 0; y < orig.rows; y++){uchar* data = orig.ptr<uchar>(y);for (x = 0; x < orig.cols; x++){sImage[(y*nWidth + x) * 3 + 0] = data[3 * x + 0];sImage[(y*nWidth + x) * 3 + 1] = data[3 * x + 1];sImage[(y*nWidth + x) * 3 + 2] = data[3 * x + 2];}}/* 彩色圖像增強 */MSRCR(sImage, nWidth, nHeight, orig.channels());for (y = 0; y < nHeight; y++){uchar* data = dst.ptr<uchar>(y);for (x = 0; x < nWidth; x++){data[3 * x + 0] = sImage[(y*nWidth + x) * 3 + 0];data[3 * x + 1] = sImage[(y*nWidth + x) * 3 + 1];data[3 * x + 2] = sImage[(y*nWidth + x) * 3 + 2];}}//顯示處理圖像imshow("Result Image", dst);waitKey(0);free(sImage);free(dImage);return 0; }下面的MSRCR是整個算法的和核心部分
/* 這個函數是算法的核心 */ /* (a) 在多個刻度處過濾,并將結果匯總 */ /* (b) 計算最終結果 */ void MSRCR(unsigned char * src, int width, int height, int bytes) {int scale, row, col;int i, j;int size;int pos;int channel;unsigned char *psrc = NULL; /* SRC圖的備份指針 */float *dst = NULL; /* 算法的浮動緩沖區 */float *pdst = NULL; /* 浮點緩沖區的備份指針 */float *in, *out;int channelsize; /* 一個通道的浮動內存緩存 */float weight;gauss3_coefs coef;float mean, var;float mini, range, maxi;float alpha;float gain;float offset;/* 分配算法所需的所有內存 */size = width * height * bytes;dst = (float *)malloc(size * sizeof(float));if (dst == NULL){printf("Failed to allocate memory");return;}memset(dst, 0, size * sizeof(float));channelsize = (width * height);in = (float *)malloc(channelsize * sizeof(float));if (in == NULL){free(dst);printf("Failed to allocate memory");return; /* 判斷輸入*/}out = (float *)malloc(channelsize * sizeof(float));if (out == NULL){free(in);free(dst);printf("Failed to allocate memory");return; /* 判斷輸出 */}/* 根據過濾器數量及其分布計算過濾尺度 */retinex_scales_distribution(RetinexScales, rvals.nscales, rvals.scales_mode, rvals.scale);/* 根據不同的尺度數進行過濾 *//* 根據一個特定的重量總結各種過濾器的結果(這里等同于所有過濾器)*/weight = 1.0f / (float)rvals.nscales;/* 根據所選的尺度,遞歸濾波算法需要不同的系數(~=高斯標準偏差)*/pos = 0;for (channel = 0; channel < 3; channel++){for (i = 0, pos = channel; i < channelsize; i++, pos += bytes){/* 0-255 => 1-256 */in[i] = (float)(src[pos] + 1.0);}//對原始圖像進行每個尺度的高斯模糊for (scale = 0; scale < rvals.nscales; scale++){compute_coefs3(&coef, RetinexScales[scale]);/* 過濾(平滑)高斯遞歸 *//* 先篩選行 */for (row = 0; row < height; row++){pos = row * width;gausssmooth(in + pos, out + pos, width, 1, &coef);}memcpy(in, out, channelsize * sizeof(float));memset(out, 0, channelsize * sizeof(float));/* 過濾(平滑)高斯遞歸 *//* 選擇列 */for (col = 0; col < width; col++){pos = col;gausssmooth(in + pos, out + pos, height, width, &coef);}/* 匯總過濾的值 *///對每個尺度下進行累加計算 Log[R(x,y)] = Log[R(x,y)] + Weight(i)* ( Log[Ii(x,y)]-Log[Li(x,y)]);//其中Weight(i)表示每個尺度對應的權重,要求各尺度權重之和必須為1,經典的取值為等權重for (i = 0, pos = channel; i < channelsize; i++, pos += bytes){dst[pos] += weight * (float)(log(src[pos] + 1.0f) - log(out[i]));}}}free(in);free(out);/* 最終計算原始值和累積濾波器值 *//* 參數增益、alpha和offset是常量 *//* Ci(x,y)=log[a Ii(x,y)]-log[ Ei=1-s Ii(x,y)] */alpha = 128.0f;gain = 1.0f;offset = 0.0f;for (i = 0; i < size; i += bytes){float logl;psrc = src + i;pdst = dst + i;logl = (float)log((float)psrc[0] + (float)psrc[1] + (float)psrc[2] + 3.0f);pdst[0] = gain * ((float)(log(alpha * (psrc[0] + 1.0f)) - logl) * pdst[0]) + offset;pdst[1] = gain * ((float)(log(alpha * (psrc[1] + 1.0f)) - logl) * pdst[1]) + offset;pdst[2] = gain * ((float)(log(alpha * (psrc[2] + 1.0f)) - logl) * pdst[2]) + offset;}/* 根據一階和二階的統計數據調整顏色的動態 *//* 使用方差可以控制顏色的飽和度 */pdst = dst;//計算RGB各通道數據的均值Mean和均方差Varcompute_mean_var(pdst, &mean, &var, size, bytes);mini = mean - rvals.cvar*var;maxi = mean + rvals.cvar*var;range = maxi - mini;if (!range) range = 1.0;//對Log[R(x,y)]的每一個值,進行線性映射for (i = 0; i < size; i += bytes){psrc = src + i;pdst = dst + i;for (j = 0; j < 3; j++){float c = 255 * (pdst[j] - mini) / range;psrc[j] = (unsigned char)clip(c, 0, 255);}}free(dst); }計算期望分布的尺度
void retinex_scales_distribution(float* scales, int nscales, int mode, int s) {if (nscales == 1){/* 一個參數選擇中等尺度 */scales[0] = (float)s / 2;}else if (nscales == 2){/* 兩個參數選擇中和大尺度*/scales[0] = (float)s / 2;scales[1] = (float)s;}else{float size_step = (float)s / (float)nscales;int i;/* 按照處理模式進行處理 */switch (mode){case RETINEX_UNIFORM:for (i = 0; i < nscales; ++i)scales[i] = 2.0f + (float)i * size_step;break;case RETINEX_LOW:size_step = (float)log(s - 2.0f) / (float)nscales;for (i = 0; i < nscales; ++i)scales[i] = 2.0f + (float)pow(10, (i * size_step) / log(10));break;case RETINEX_HIGH:size_step = (float)log(s - 2.0) / (float)nscales;for (i = 0; i < nscales; ++i)scales[i] = s - (float)pow(10, (i * size_step) / log(10));break;default:break;}} }計算一次平均值和方差
void compute_mean_var(float *src, float *mean, float *var, int size, int bytes) {float vsquared;int i, j;float *psrc;vsquared = 0.0f;*mean = 0.0f;for (i = 0; i < size; i += bytes){psrc = src + i;for (j = 0; j < 3; j++){/* 平均值 */*mean += psrc[j];/* 方差 */vsquared += psrc[j] * psrc[j];}}*mean /= (float)size; /* mean */vsquared /= (float)size; /* mean (x^2) */*var = (vsquared - (*mean * *mean));*var = (float)sqrt(*var); /* var */ }高斯模糊的快速計算?
關于高斯模糊如果有不清楚的可以參考這篇文章
https://www.cnblogs.com/invisible2/p/9177018.html
void compute_coefs3(gauss3_coefs * c, float sigma) {float q, q2, q3;q = 0;if (sigma >= 2.5f){q = 0.98711f * sigma - 0.96330f;}else if ((sigma >= 0.5f) && (sigma < 2.5f)){q = 3.97156f - 4.14554f * (float)sqrt((double)1 - 0.26891 * sigma);}else{q = 0.1147705018520355224609375f;}q2 = q * q;q3 = q * q2;c->b[0] = (1.57825f + (2.44413f*q) + (1.4281f *q2) + (0.422205f*q3));c->b[1] = ((2.44413f*q) + (2.85619f*q2) + (1.26661f *q3));c->b[2] = (-((1.4281f*q2) + (1.26661f *q3)));c->b[3] = ((0.422205f*q3));c->B = 1.0f - ((c->b[1] + c->b[2] + c->b[3]) / c->b[0]);c->sigma = sigma;c->N = 3; }高斯平滑
void gausssmooth(float *in, float *out, int size, int rowstride, gauss3_coefs *c) {int i, n, bufsize;float *w1, *w2;/* forward pass */bufsize = size + 3;size -= 1;w1 = (float *)malloc(bufsize * sizeof(float));w2 = (float *)malloc(bufsize * sizeof(float));w1[0] = in[0];w1[1] = in[0];w1[2] = in[0];for (i = 0, n = 3; i <= size; i++, n++){w1[n] = (float)(c->B*in[i*rowstride] +((c->b[1] * w1[n - 1] +c->b[2] * w1[n - 2] +c->b[3] * w1[n - 3]) / c->b[0]));}/* backward pass */w2[size + 1] = w1[size + 3];w2[size + 2] = w1[size + 3];w2[size + 3] = w1[size + 3];for (i = size, n = i; i >= 0; i--, n--){w2[n] = out[i * rowstride] = (float)(c->B*w1[n] +((c->b[1] * w2[n + 1] +c->b[2] * w2[n + 2] +c->b[3] * w2[n + 3]) / c->b[0]));}free(w1);free(w2); }輸入的原圖
經過retinex算法處理的圖,可以看到原圖幾乎什么都看不清,但是retinex算法可以將圖片的顏色較好的還原出來。
代碼已經傳到了csdn上,下載鏈接是
https://download.csdn.net/download/weixin_42521239/11165325
沒有積分的小伙伴可以在評論中留下你的郵箱,我發給你
總結
以上是生活随笔為你收集整理的图像增强--视网膜皮层Retinex算法(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 工作398-关于e.currentTar
- 下一篇: 实现深拷贝的几种方法
