├── .gitignore
├── README.md
├── debug
├── OpenCV_test
└── Prb.csv
├── imgs
├── Bilinear_example.png
├── Bilnear_dst.bmp
├── GBTF_dst.bmp
├── GBTF_example.png
└── bayer_pattern_img.bmp
└── src
├── GBTF.cpp
├── GBTF.hpp
└── main.cpp
/.gitignore:
--------------------------------------------------------------------------------
1 | *.DS_Store
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | I have introduced the basic color interpolation algorithm in my "Basic_Color_Interpolation" reop. But simple color interpolation method will cause a lot of artifacts, such as false color, decreasing resolution, aliasing...
2 | These artifacts usually due to we simply interpolate the missing pixel value with its neighbor pixel value and forget to consider the relationship of R,G and B.
3 | We should consider the directional color difference or gradients of every pixel and using this correction to interpolate the missing color value.
4 |
5 | This repo is the implementing of "Gradient Based Threshold Free CFA Interpolation" algorithm. It first interpolates the green channels of image using directional weighting by estimating the color difference and gradients information of image.
6 | Then it interpolates the Red and Blue channels by a filter comes from "Spatially adaptive color filter array interpolation for noiseless and noisy data" paper and bilinear method.
7 |
8 | This is the bayer image from my "Basic_Color_Interpolation" reop which the bayer pattern is GRBG.
9 | 
10 |
11 | This is the result from bilinear method which we can see a lot of false color effect.
12 | 
13 |
14 | This is the result from GBTF method and it reduces the artifacts very effectively.
15 | 
16 |
17 |
18 | reference:
19 | 1.https://ieeexplore.ieee.org/document/5654327 (GRADIENT BASED THRESHOLD FREE COLOR FILTER ARRAY INTERPOLATION)
20 | 2.https://onlinelibrary.wiley.com/doi/abs/10.1002/ima.20109 (Spatially adaptive color filter array interpolation for noiseless and noisy data)
--------------------------------------------------------------------------------
/debug/OpenCV_test:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RayXie29/GBTF_Color_Interpolation/8a3faa7a57a181a4c7bee99ab365198dff293f71/debug/OpenCV_test
--------------------------------------------------------------------------------
/debug/Prb.csv:
--------------------------------------------------------------------------------
1 | 0,0,-0.0313,0,-0.0313,0,0
2 | 0,0,0,0,0,0,0
3 | -0.0313,0,0.3125,0,0.3125,0,-0.0313
4 | 0,0,0,0,0,0,0
5 | -0.0313,0,0.3125,0,0.3125,0,-0.0313
6 | 0,0,0,0,0,0,0
7 | 0,0,-0.0313,0,-0.0313,0,0
--------------------------------------------------------------------------------
/imgs/Bilinear_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RayXie29/GBTF_Color_Interpolation/8a3faa7a57a181a4c7bee99ab365198dff293f71/imgs/Bilinear_example.png
--------------------------------------------------------------------------------
/imgs/Bilnear_dst.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RayXie29/GBTF_Color_Interpolation/8a3faa7a57a181a4c7bee99ab365198dff293f71/imgs/Bilnear_dst.bmp
--------------------------------------------------------------------------------
/imgs/GBTF_dst.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RayXie29/GBTF_Color_Interpolation/8a3faa7a57a181a4c7bee99ab365198dff293f71/imgs/GBTF_dst.bmp
--------------------------------------------------------------------------------
/imgs/GBTF_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RayXie29/GBTF_Color_Interpolation/8a3faa7a57a181a4c7bee99ab365198dff293f71/imgs/GBTF_example.png
--------------------------------------------------------------------------------
/imgs/bayer_pattern_img.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RayXie29/GBTF_Color_Interpolation/8a3faa7a57a181a4c7bee99ab365198dff293f71/imgs/bayer_pattern_img.bmp
--------------------------------------------------------------------------------
/src/GBTF.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "GBTF.hpp"
3 | #include
4 | #include
5 |
6 |
7 | void to_SingleChannel(cv::Mat &src,cv::Mat &dst)
8 | {
9 | dst = cv::Mat(src.size(),CV_8UC1,cv::Scalar(0));
10 | for(int i=0;i(i);
13 | uchar *dptr = dst.ptr(i);
14 | for(int j=0;j &WeightTable,cv::Mat &HGradientMap, cv::Mat &VGradientMap)
61 | {
62 | int i,j,k;
63 | int NSEW[4][2] = { {-4,-2}, {0,-2} , {-2,-4}, {-2,0} };
64 | for (i = 5, k = 0; i < HGradientMap.rows - 5; ++i)
65 | {
66 | j = i%2? 6 : 5;
67 | for (; j < HGradientMap.cols - 5; j+=2)
68 | {
69 | //R & B pixel location
70 | for(int dir=0;dir<4;++dir,++k)
71 | {
72 | for(int a=i+NSEW[dir][0] ; a<=i+NSEW[dir][0]+4 ; ++a)
73 | {
74 | float *VGMPtr = VGradientMap.ptr(a);
75 | float *HGMPtr = HGradientMap.ptr(a);
76 | for(int b=j+NSEW[dir][1]; b<=j+NSEW[dir][1]+4 ;++b)
77 | {
78 | if(dir<2) { WeightTable[k] += VGMPtr[b]; }
79 | else { WeightTable[k] += HGMPtr[b]; }
80 | }
81 | }
82 | if(WeightTable[k]) { WeightTable[k] = 1.0 / (WeightTable[k]*WeightTable[k]); }
83 | }
84 | }
85 | }
86 | }
87 |
88 | void PrbMat(cv::Mat &Prb)
89 | {
90 | std::fstream infile("./Prb.csv", std::ios::in);
91 | if (!infile)
92 | {
93 | std::cerr << "Open the file error" << std::endl;
94 | exit(EXIT_FAILURE);
95 | }
96 | std::string line;
97 | int i = 0, j = 0;
98 | while (getline(infile, line))
99 | {
100 | float *PrbP = Prb.ptr(i++);
101 | j = 0;
102 | std::istringstream templine(line);
103 | std::string data;
104 | while (getline(templine, data, ',')) { PrbP[j++] = atof(data.c_str()); }
105 | }
106 | infile.close();
107 | }
108 |
109 | void GBTF_CFAInterpolation(cv::Mat &Bayer,cv::Mat &Dst,int BayerPatternFlag = 0)
110 | {
111 | cv::Mat Src = Bayer.clone();
112 | if (BayerPatternFlag == 1) { cv::copyMakeBorder(Src, Src, 0, 0, 1, 1, cv::BORDER_REFLECT_101); }
113 | else if (BayerPatternFlag == 2) { cv::copyMakeBorder(Src, Src, 1, 1, 1, 1, cv::BORDER_REFLECT_101); }
114 | else if (BayerPatternFlag == 3) { cv::copyMakeBorder(Src, Src, 1, 1, 0, 0, cv::BORDER_REFLECT_101); }
115 | else if (BayerPatternFlag)
116 | {
117 | std::cerr << "Please select the right Bayer Pattern , default(0) ->GRBG , 1->RGGB , 2->GBRG , 3->BGGR" << std::endl;
118 | return;
119 | }
120 |
121 | Dst = Src.clone();
122 | cv::Mat src1ch;
123 | to_SingleChannel(Src, src1ch);
124 | int i,j,k;
125 | int channels = 3;
126 | int width = Src.cols, height = Src.rows;
127 |
128 |
129 | //Calculate Horizontal and vertical color difference maps
130 | cv::Mat HCDMap,VCDMap;
131 | CalHVcolordiff(src1ch, HCDMap, VCDMap);
132 |
133 | //Calculate Horizontal and vertical color difference gradients
134 | cv::copyMakeBorder(HCDMap, HCDMap, 5, 5, 5, 5, cv::BORDER_CONSTANT, cv::Scalar(0));
135 | cv::copyMakeBorder(VCDMap, VCDMap, 5, 5, 5, 5, cv::BORDER_CONSTANT, cv::Scalar(0));
136 |
137 | cv::Mat HGradientMap,VGradientMap;
138 | CalHVcolordiffGrad(HCDMap, VCDMap, HGradientMap, VGradientMap);
139 |
140 | //weight table calculation
141 | int WeightTableSize = height*(int)(width / 2);
142 | std::vector WeightTable(WeightTableSize * 4);
143 | CalWeightingTable(WeightTable, HGradientMap, VGradientMap);
144 |
145 | //Target Pixel Gradient Map
146 | cv::Mat TPdiff(height, width, CV_32FC1, cv::Scalar(0));
147 |
148 | //Interpolate green value at blue and red pixel location
149 | for(i=5, k=0; i(i-5);
153 | uchar *DstPtr = Dst.ptr(i-5);
154 | for(;j(4,idx) + NSKernel[idx][4] * Vroi.at(idx,4);
177 | }
178 | TPPtr[j-5] /= totalWeight;
179 | }
180 | DstPtr[(j-5)*channels+1]= cv::saturate_cast(DstPtr[(j-5)*channels+i%2+!(j%2)] + TPPtr[j-5]);
181 | }
182 | }
183 |
184 | // Prb.csv reading
185 | cv::Mat Prb(7, 7, CV_32FC1, cv::Scalar(0));
186 | PrbMat(Prb);
187 |
188 | cv::copyMakeBorder(TPdiff, TPdiff, 3, 3, 3, 3, cv::BORDER_CONSTANT, cv::Scalar(0));
189 |
190 | //Interpolate R,B channel in blue and red pixel locations
191 | for(i=3;i(i-3);
195 | for(;j(x);
203 | float *TProiPtr = TProi.ptr(x);
204 | for(int y=0;y<7;y+=2) { sum += PrbPtr[y]* TProiPtr[y]; }
205 | }
206 | DPtr[(j-3)*channels + !(i%2)+j%2 ] = cv::saturate_cast(DPtr[(j-3)*channels + 1 ] - sum);
207 | }
208 | }
209 |
210 |
211 | //Interpolate R,B channel on G pixel
212 | int NSEW[4][2] = { {-1,0} , {1,0}, {0,-1}, {0,1} };
213 | for(i=0;i(i);
216 | j = i%2?1:0;
217 | for(;j=0 && x=0 && y(x,y)[1] - Dst.at(x,y)[0];
228 | GRdiff += Dst.at(x,y)[1] - Dst.at(x,y)[2];
229 | }
230 | }
231 | DstPtr[j*channels+2] = cv::saturate_cast(G - GRdiff/4);
232 | DstPtr[j*channels] = cv::saturate_cast(G-GBdiff/4);
233 | }
234 | }
235 |
236 | if (BayerPatternFlag == 1){ Dst = Dst(cv::Rect(1, 0, width - 2, height)); }
237 | else if (BayerPatternFlag == 2) { Dst = Dst(cv::Rect(1, 1, width - 2, height - 2)); }
238 | else if (BayerPatternFlag == 3) { Dst = Dst(cv::Rect(0, 1, width, height - 2)); }
239 | }
240 |
241 |
--------------------------------------------------------------------------------
/src/GBTF.hpp:
--------------------------------------------------------------------------------
1 |
2 | #ifndef GBTF_hpp
3 | #define GBTF_hpp
4 |
5 | #include
6 | void GBTF_CFAInterpolation(cv::Mat &Bayer,cv::Mat &Dst,int BayerPatternFlag);
7 |
8 | #endif /* GBTF_hpp */
9 |
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | /****************************************************/
4 | #include "GBTF.hpp"
5 | using namespace std;
6 |
7 | int main(int argc, const char * argv[]) {
8 |
9 | cv::Mat img = cv::imread("./imgs/bayer_pattern_img.bmp",cv::IMREAD_COLOR);
10 | cv::Mat dst;
11 |
12 | GBTF_CFAInterpolation(img, dst, 0);
13 |
14 |
15 | cv::imshow("bayer_pattern_img.bmp",img);
16 | cv::imshow("GBTF_dst.bmp",dst);
17 |
18 | cv::waitKey(0);
19 | cv::destroyAllWindows();
20 | cv::imwrite("GBTF_dst.bmp",dst);
21 | }
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------