├── imgs ├── result.bmp ├── original.bmp ├── afterCorrection.bmp └── beforeCorrection.bmp ├── src ├── ColorAberrationCorrection.h ├── main.cpp └── ColorAberrationCorrection.cpp └── README.md /imgs/result.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RayXie29/Chromatic_aberration_correction/HEAD/imgs/result.bmp -------------------------------------------------------------------------------- /imgs/original.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RayXie29/Chromatic_aberration_correction/HEAD/imgs/original.bmp -------------------------------------------------------------------------------- /imgs/afterCorrection.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RayXie29/Chromatic_aberration_correction/HEAD/imgs/afterCorrection.bmp -------------------------------------------------------------------------------- /imgs/beforeCorrection.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RayXie29/Chromatic_aberration_correction/HEAD/imgs/beforeCorrection.bmp -------------------------------------------------------------------------------- /src/ColorAberrationCorrection.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | void rmCA(std::vector &bgrVec, int threshold); 5 | void CACorrection(cv::Mat &Src, cv::Mat &Dst); -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | /*---------------------------------------------------------------------*/ 4 | #include "CAC.h" 5 | 6 | int main(int argc, char *argv[]) { 7 | 8 | 9 | cv::Mat src = cv::imread(".\\imgs\\original.bmp", cv::IMREAD_COLOR); 10 | cv::Mat dst; 11 | 12 | CACorrection(src, dst); 13 | 14 | cv::imshow("original", src); 15 | cv::imshow("result", dst); 16 | 17 | 18 | cv::imwrite(".\\imgs\\result.bmp", dst); 19 | 20 | cv::waitKey(0); 21 | cv::destroyAllWindows(); 22 | 23 | return 0; 24 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chromatic aberration correction algorithm 2 | 3 | This repo is the implementation of paper "Removing chromatic aberration by digital image processing"
4 | Chromatic aberration is due to different indices of color in light. And most of the time, it looked like color fringes along the boundary or color blur.
5 | This paper observe the color behavior on edges in image and correct the chrmoatic aberration by shifting the abnormal color varying into a reasonable range. First we need to set a threshold to find the edge where we will start to estimate the reasonable range for this area. Then we use maximum and minimum color difference between B&G and R&G to be the BG/RG color difference threshold of this range. If we found a pixel which its R-G and B-G bigger or smaller than color difference threshold in this range, then we use this threshold to replace its color difference. Also we need to do above steps in both horizontal and vertical direction to correct all the color aberration in image.
6 |
7 | Here is the zoom in view of original image
8 | As you can see, there are many color fringes on the edge of lamp
9 | ![alt text](https://raw.githubusercontent.com/RayXie29/Chromatic_aberration_correction/master/imgs/beforeCorrection.bmp) 10 |
11 |
12 |
13 | Here is the zoom in view after correction
14 | Teh chromatic aberration were corrected and the quality of other region remain almost the same.
15 | ![alt text](https://raw.githubusercontent.com/RayXie29/Chromatic_aberration_correction/master/imgs/afterCorrection.bmp) 16 | 17 |
18 |
19 | Reference:
20 | 1.https://www.spiedigitallibrary.org/journals/Optical-Engineering/volume-49/issue-6/067002/Removing-chromatic-aberration-by-digital-image-processing/10.1117/1.3455506.short?SSO=1 (Removing chromatic aberration by digital image processing)
21 | -------------------------------------------------------------------------------- /src/ColorAberrationCorrection.cpp: -------------------------------------------------------------------------------- 1 | 2 | void rmCA(std::vector &bgrVec, int threshold) 3 | { 4 | int height = bgrVec[0].rows, width = bgrVec[0].cols; 5 | 6 | for (int i = 0; i < height; ++i) 7 | { 8 | uchar *bptr = bgrVec[0].ptr(i); 9 | uchar *gptr = bgrVec[1].ptr(i); 10 | uchar *rptr = bgrVec[2].ptr(i); 11 | 12 | for (int j = 1; j < width - 1; ++j) 13 | { 14 | //find the edge by finding green channel gradient bigger than threshold 15 | if (abs(gptr[j + 1] - gptr[j - 1]) >= threshold) 16 | { 17 | // +/- sign of this edge 18 | int sign = 0; 19 | if (gptr[j + 1] - gptr[j - 1] > 0) { sign = 1; } 20 | else { sign = -1; } 21 | 22 | //Searching the boundary for correction range 23 | int lpos = j-1, rpos = j+1; 24 | for (; lpos > 0; --lpos) 25 | { 26 | //make sure the gradient is the same sign with edge 27 | int ggrad = (gptr[lpos + 1] - gptr[lpos - 1])*sign; 28 | int bgrad = (bptr[lpos + 1] - bptr[lpos - 1])*sign; 29 | int rgrad = (rptr[lpos + 1] - rptr[lpos - 1])*sign; 30 | if (std::max(std::max(bgrad, ggrad), rgrad) < threshold) { break; } 31 | } 32 | lpos -= 1; 33 | for (; rpos < width - 1; ++rpos) 34 | { 35 | //make sure the gradient is the same sign with edge 36 | int ggrad = (gptr[rpos + 1] - gptr[rpos - 1])*sign; 37 | int bgrad = (bptr[rpos + 1] - bptr[rpos - 1])*sign; 38 | int rgrad = (rptr[rpos + 1] - rptr[rpos - 1])*sign; 39 | if (std::max(std::max(bgrad, ggrad), rgrad) < threshold) { break; } 40 | } 41 | rpos += 1; 42 | 43 | //record the maximum and minimum color difference between R&G and B&G of range boundary 44 | int bgmaxVal = std::max(bptr[lpos] - gptr[lpos], bptr[rpos] - gptr[rpos]); 45 | int bgminVal = std::min(bptr[lpos] - gptr[lpos], bptr[rpos] - gptr[rpos]); 46 | int rgmaxVal = std::max(rptr[lpos] - gptr[lpos], rptr[rpos] - gptr[rpos]); 47 | int rgminVal = std::min(rptr[lpos] - gptr[lpos], rptr[rpos] - gptr[rpos]); 48 | 49 | for (int k = lpos; k <= rpos; ++k) 50 | { 51 | int bdiff = bptr[k] - gptr[k]; 52 | int rdiff = rptr[k] - gptr[k]; 53 | 54 | //Replace the B or R value if its color difference of R/G and B/G is bigger(smaller) 55 | //than maximum(minimum) of color difference on range boundary 56 | bptr[k] = cv::saturate_cast( bdiff > bgmaxVal ? bgmaxVal + gptr[k] : 57 | (bdiff < bgminVal ? bgminVal + gptr[k] : bptr[k]) ); 58 | rptr[k] = cv::saturate_cast( rdiff > rgmaxVal ? rgmaxVal + gptr[k] : 59 | (rdiff < rgminVal ? rgminVal + gptr[k] : rptr[k]) ); 60 | } 61 | j = rpos - 2; 62 | } 63 | } 64 | } 65 | } 66 | 67 | void CACorrection(cv::Mat &Src, cv::Mat &Dst) 68 | { 69 | std::vector bgrVec(3); 70 | //split the color image into individual color channel for convenient in calculation 71 | cv::split(Src, bgrVec); 72 | 73 | //setting threshold to find the edge and correction range(in g channel) 74 | int threshold = 30; 75 | 76 | rmCA(bgrVec, threshold); 77 | 78 | //transpose the R,G B channel image to correct chromatic aberration in vertical direction 79 | bgrVec[0] = bgrVec[0].t(); 80 | bgrVec[1] = bgrVec[1].t(); 81 | bgrVec[2] = bgrVec[2].t(); 82 | 83 | rmCA(bgrVec, threshold); 84 | 85 | cv::merge(bgrVec, Dst); 86 | //rotate the image back to original position 87 | cv::transpose(Dst.clone(), Dst); 88 | } --------------------------------------------------------------------------------