【花書DL-book】區域性對比度歸一化 LCN
阿新 • • 發佈:2019-01-28
實現方法來自於花書(deep-learning book),P387
// written down after reading deep-learning book chinese edition P389 // all about LCN(local contrast normalization) compared to GCN(general contrast normalization) // Also compared to adaptive-threshold and sobel method in OpenCV // Author: Jie Li(Sirius) // blog : http://blog.csdn.net/Sirius_0 // github: iwhm // 25/02/2018 #include <stdlib.h> #include <opencv2> #include <opencv2\imgproc> int main(void) { cv::Mat yuan; cv::Mat src; // sub_windows size int sub_win_size = 3; yuan = cv::imread("./lena.jpg"); if(yuan.empty()) { assert(0); return -1; } if(yuan.channels() == 3) { cv::cvtColor(yuan, src, cv::COLOR_BGR2GRAY); } else { src = yuan.clone(); } cv::Mat s_dst(src.rows, src.cols, CV_8UC1, cv::Scalar(0, 0, 0)); cv::Mat g_dst(src.rows, src.cols, CV_8UC1, cv::Scalar(0, 0, 0)); /************ dl-book chinese edition P390 use variance and standard deviation ************/ for(int rr = sub_win_size / 2; rr < src.rows - (sub_win_size / 2 + 1); rr++) { for(int cc = sub_win_size / 2; cc < src.cols - (sub_win_size / 2 + 1); cc++) { // calculate total value int total_val = 0; for(int i = - (win_size / 2); i < (win_size / 2 + 1); i++) { for(int k = - (win_size / 2); k < (win_size / 2 + 1); k++) { total_val += src.at<unsigned char>(rr + k, cc + i); } } // calculate average value int avg_val = 0; avg_val = total_val / (win_size * win_size); if(avg_val == 0) { continue; } // calculate variance value long int var_val = 0; for(int i = - (win_size / 2); i < (win_size / 2 + 1); i++) { for(int k = - (win_size / 2); k < (win_size / 2 + 1); k++) { var_val = abs(avg_val - src.at<unsigned char>(rr + k, cc + i) * abs(avg_val - src.at<unsigned char>(rr + k, cc +i)); } } // calculate standard deviation int std_dev = 0; std_dev = std::sqrt(var_val) / (win_size * win_size); if(std_dev == 0) { continue; } s_dst.at<UCHAR>(rr, cc) = (abs(src.at<UCHAR>(rr, cc) - avg_val) / std_dev); } } s_dst = s_dst > 0; cv::imshow("s_dstimg", s_dst); /************ dl-book chinese edition P390 use gaussian kernel & average value ************/ // acquire a 2-D gaussian kernel cv::Mat g_kernel1, g_kernel2; g_kernel1 = cv::getGaussinaKernel(win_size, 0.0, 6); cv::transpose(cv::getGaussinaKernel(win_size, 0.0, 6), g_kernel2); cv::Mat g_2Dkernel; g_2Dkernel = g_kernel1 * g_kernel2; for(int rr = sub_win_size / 2; rr < src.rows - (sub_win_size / 2 + 1); rr++) { for(int cc = sub_win_size / 2; cc < src.cols - (sub_win_size / 2 + 1); cc++) { cv::Mat sub_win(win_size, win_size, CV_8UC1, cv::Scalar(0, 0, 0)); cv::Mat tmp_sub_win(win_size, win_size, CV_8UC1, cv::Scalar(0, 0, 0)); for(int i = - (win_size / 2); i < (win_size / 2 + 1); i++) { for(int k = - (win_size / 2); k < (win_size / 2 + 1); k++) { tmp_sub_win.at<UCHAR>(k + win_size / 2, i + win_size / 2) = tmp.at<UCHAR>(rr + k, cc + i); } } sub_win = tmp_sub_win.mul(g_2Dkernel); for(int m = 0; m < win_size; m++) { for(int n = 0; n < win_size; n++) { g_dst.at<UCHAR>(rr, cc) += sub_win.at<UCHAR>(m, n); } } } } g_dst = g_dst > 0; cv::imshow("g_dstimg", g_dst); // existed method for comparison // sobel method cv::Mat sobimg(src.rows, src.cols, CV_8UC1, cv::Scalar(0, 0, 0)); cv::Sobel(src, sobimg, 0, 1, 1, 3, 1, 0, cv::BORDER_DEFAULT); sobimg = sobimg > 0; cv::imshow("sobimg", sobimg); // adaptive-threshold method cv::Mat adaimg(src.rows, src.cols, CV_8UC1, cv::Scalar(0, 0, 0)); cv::adaptiveThreshold(src, adaimg, 255, cv::ADAPTIVE_THRESH_GAUSSIAN_C, cv::THRESH_BINARY_INV, 25, 18); adaimg = adaimg > 0; cv::imshow("adaimg", adaimg); cv::waitKey(0); return 0; }