Hello,
I want to do 16bit image vignetting correction and for this, i used below link
https://github.com/GUOYI1/Vignetting_corrector/tree/master/C%2B%2B/Vig_Correction
This is in type IPLImage, but now IPLImage is outdated that's why I converted into Mat type .
This logic is worked correctly for 8bit image but when I converted for 16bit image(changes like unsigned char to unsigned short) its not working properly.
Please give me any suggetions.
Below is my code :
#include<iostream>
include "opencv2/core.hpp"
include "opencv2/imgproc.hpp"
include "opencv2/imgcodecs.hpp"
include "opencv2/highgui.hpp"
include <iostream>
include <fstream>
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
#include <fstream>
using namespace std;
using namespace cv;
cv;
void mult(double m1,double *m1,double *m2,double *result,int i_1,int j_12,int j_2)
{
int i,j,k;
for(i=0;i<i_1;i++) for(j="0;j<j_2;j++)" {="" result[i<="" em="">j_2+j]=0.0;
for(i=0;i<i_1;i++)
for(j=0;j<j_2;j++)
{
result[i*j_2+j]=0.0;
for(k=0;k<j_12;k++)
result[i*j_2+j] += m1[i*j_12+k]*m2[j+k*j_2];
}
return;
}
/Matrix Inverse/
}
/*Matrix Inverse*/
int invers_matrix(double m1,int *m1,int n)
{
int *is,
js;
*is,*js;
int i,j,k,l,u,v;
double temp,max_v;
is=(int
)malloc(nsizeof(int));
*)malloc(n*sizeof(int));
js=(int
)malloc(nsizeof(int));
*)malloc(n*sizeof(int));
if(is==NULL||js==NULL)
{
printf("out of memory!\n");
return(0);
}
for(k=0;k<n;k++) {="" max_v="0.0;" for(i="k;i<n;i++)" for="" (j="k;" j="" <="" n;="" j++)="" {="" temp="fabs(m1[i*n" +="" j]);="" if="" (temp="" >="" max_v)="" {="" max_v="temp;" is[k]="i;" js[k]="j;" }="" }="" if(max_v="=0.0)" {="" free(is);="" free(js);="" printf("invers="" is="" not="" availble!\n");="" return(0);="" }="" if(is[k]!="k)" {="" for="" (j="0;" j<n;="" j++)="" {="" u="k*n" +="" j;="" v="is[k]" *="" n="" +="" j;="" temp="m1[u];" m1[u]="m1[v];" m1[v]="temp;" }="" }<="" p="">
for(k=0;k<n;k++)
{
max_v=0.0;
for(i=k;i<n;i++)
for (j = k; j < n; j++)
{
temp = fabs(m1[i*n + j]);
if (temp > max_v)
{
max_v = temp; is[k] = i; js[k] = j;
}
}
if(max_v==0.0)
{
free(is); free(js);
printf("invers is not availble!\n");
return(0);
}
if(is[k]!=k)
{
for (j = 0; j<n; j++)
{
u = k*n + j; v = is[k] * n + j;
temp = m1[u]; m1[u] = m1[v]; m1[v] = temp;
}
}
if(js[k]!=k)
{
for (i = 0; i<n; i++) {
u = i*n + k; v = i*n + js[k];
temp = m1[u]; m1[u] = m1[v]; m1[v] = temp;
}
}
l=k*n+k;
m1[l]=1.0/m1[l];
for(j=0;j<n;j++)
if(j!=k)
{
u=k*n+j;
m1[u]*=m1[l];
}
for (i = 0; i < n; i++)
{
if (i != k)
for (j = 0; j < n; j++)
if (j != k)
{
u = i*n + j;
m1[u] -= m1[i*n + k] * m1[k*n + j];
}
}
for(i=0;i<n;i++)
{
if (i != k)
{
u = i*n + k;
m1[u] *= -m1[l];
}
}
}
for(k=n-1;k>=0;k--)
{
if(js[k]!=k)
{
for (j = 0; j<n; j++) {
u = k*n + j; v = js[k] * n + j;
temp = m1[u]; m1[u] = m1[v]; m1[v] = temp;
}
}
if(is[k]!=k)
{
for (i = 0; i<n; i++) {
u = i*n + k; v = i*n + is[k];
temp = m1[u]; m1[u] = m1[v]; m1[v] = temp;
}
}
}
free(is);
free(js);
return(1);
}
/Matrix Transpose/
/*Matrix Transpose*/
void transpose(double
m1,double *m1,double *m2,int m,int n)
{
int i,j;
for(i=0;i<m;i++) for(j="0;j<n;j++)" m2[j<="" em="">m+i]=m1[i*n+j];
for(i=0;i<m;i++)
for(j=0;j<n;j++)
m2[j*m+i]=m1[i*n+j];
return;
} }
int VignettingCorrectionUsingRG_16bit(unsigned short* pImage, int ht, int wd, vector<double>& vp)
{
ofstream myfile;
myfile.open("E:\Vignetting_image\vig_vector_16bit_.txt");
myfile.open("E:\\Vignetting_image\\vig_vector_16bit_.txt");
int halfWd =
wd0.5;
wd*0.5;
int halfHt =
ht0.5;
ht*0.5;
int nRadius = sqrt(double(halfHt*halfHt + halfWd*halfWd)) + 0.5 + 1;
cout << "nRadius :" << nRadius << endl;
vp.resize(nRadius);
double* weight = (double*)malloc(ht*wd * sizeof(double));
//memset(weight, 1, ht*wd*sizeof(double));
for (int i = 0; i < ht*wd; i++)
weight[i] = 1;
double* rgImage = (double*)malloc(ht*wd * sizeof(double));
memset(rgImage, 0, ht*wd * sizeof(double));
double* A = (double*)malloc(nRadius * sizeof(double));
double* At = (double*)malloc(nRadius * sizeof(double));
double* AtA = (double*)malloc(nRadius*nRadius * sizeof(double));
double* sAtA = (double*)malloc(nRadius*nRadius * sizeof(double));
double* sAtL = (double*)malloc(nRadius * sizeof(double));
double* result = (double*)malloc(nRadius * sizeof(double));
double* mB = (double*)malloc(nRadius*nRadius * sizeof(double));
memset(mB, 0, nRadius*nRadius * sizeof(double));
double* mBt = (double*)malloc(nRadius*nRadius * sizeof(double));
memset(mBt, 0, nRadius*nRadius * sizeof(double));
double* mBtB = (double*)malloc(nRadius*nRadius * sizeof(double));
memset(mBtB, 0, nRadius*nRadius * sizeof(double));
//smooth constrait
//lambda*(2*numPixels/numR)
double lamdaS = 0.02 * 2 * (wd*ht) / double(nRadius);
cout << "lamdaS :" << lamdaS << endl;
myfile<< "lamdaS :" << lamdaS << endl;
for (int i = 1; i<nRadius - 1; i++)
{
mB[i*nRadius + i] = -2;//*lamdaS;
mB[i*nRadius + i - 1] = 1; //*lamdaS;
mB[i*nRadius + i + 1] = 1; //*lamdaS;
}
//matrix_print(nRadius, nRadius, mB);
cout << nRadius << endl;
cout << mB << endl;
//PrintMatrix(mB, nRadius, nRadius);
transpose(mB, mBt, nRadius, nRadius);
mult(mBt, mB, mBtB, nRadius, nRadius, nRadius);
//PrintMatrix(mBtB, nRadius, nRadius);
//calculate the radial gradients of image
double shift = 1;
double eps = 0.000001;
for (int j = 1; j<ht; j++)
{
for (int i = 1; i<wd; i++)
{
int cx = i - halfWd;
int cy = j - halfHt;
//calculate the radius
int radius = sqrt(double(cx*cx + cy*cy)) + 0.5;
//calculate the gradient
double dx = log(double(pImage[j*wd + i]) + shift) - log(double(pImage[j*wd + i - 1]) + shift);
double dy = log(double(pImage[j*wd + i]) + shift) - log(double(pImage[(j - 1)*wd + i]) + shift);
//calculate the radial gradient
double rg = double(cx*dx + cy*dy) / sqrt(double(cx*cx + cy*cy) + eps);
rgImage[j*wd + i] = rg;
myfile << rg << endl;
}
}
//PrintMatrix(rgImage, ht, wd);
//weighted least square solution
printf("\n WLS... \n");
for (int iterIndex = 0; iterIndex<5; iterIndex++)
{
memset(sAtA, 0, nRadius*nRadius * sizeof(double));
memset(sAtL, 0, nRadius * sizeof(double));
for (int j = 1; j<ht; j++)
for (int i = 1; i<wd; i++)
{
//printf("%d %d \n", j, i);
memset(A, 0, nRadius * sizeof(double));
memset(At, 0, nRadius * sizeof(double));
memset(AtA, 0, nRadius*nRadius * sizeof(double));
//calculate the radius
int cx = i - halfWd;
int cy = j - halfHt;
int radius = sqrt(double(cx*cx + cy*cy)) + 0.5;
double rg = rgImage[j*wd + i];
//calculate the AtA of each pixel
double right = 0;
if (radius>0 && radius<nRadius)
{
A[radius] = 1;
A[radius - 1] = -1;
right = rg;
}
//for (int i = 0; i < nRadius; i++)
// cout << A[i] << " ";
//cout << endl;
for (int k = 0; k<nRadius; k++)
At[k] = A[k];
mult(At, A, AtA, nRadius, 1, nRadius);
//PrintMatrix(AtA, nRadius, nRadius);
//sum of AtA
double w2 = weight[j*wd + i] * weight[j*wd + i];
//printf("%d %d %lf \n", j, i, w2);
for (int k = 0; k<nRadius*nRadius; k++)
{
sAtA[k] += AtA[k] * w2;
}
for (int k = 0; k<nRadius; k++)
{
sAtL[k] += At[k] * right*w2;
}
}
///////////////////////////// adding constraints ///////////////////////
//smooth constraint
for (int i = 0; i<nRadius*nRadius; i++)
sAtA[i] += lamdaS*lamdaS*mBtB[i];
//vignetting value constraint, make them close to 1
double eps = 0.03;
for (int i = 0; i<nRadius; i++)
sAtA[i*nRadius + i] += eps;
//////////////////////////////////////////////////////////////////////////
invers_matrix(sAtA, nRadius);
mult(sAtA, sAtL, result, nRadius, nRadius, 1);
//printf("vignetting paras..... \n");
for (int i = 0; i<nRadius; i++)
{
vp[i] = result[i];
//cout << result[i] << endl;
//cout << vp[i] << endl;
}
//update weight
double alpha = 0.3;
for (int j = 1; j<ht; j++)
for (int i = 1; i<wd; i++)
{
double rz; //radial gradient of image
double rv; //radial gradient of vignetting paras
int cx = i - halfWd;
int cy = j - halfHt;
//calculate the radius
int radius = sqrt(double(cx*cx + cy*cy)) + 0.5;
radius = max(1, min(nRadius - 1, radius));
//rv = log(vp[radius])-log(vp[radius-1]);
rv = vp[radius] - vp[radius - 1];
rz = rgImage[j*wd + i];
double s1 = fabs(rz - rv); //sqrt( (rz-rv)*(rz-rv));
double s2 = alpha*pow(s1, alpha - 1);
weight[j*wd + i] = exp(-s1)*(1 - exp(-s2));
}
}
//for (int i = 0; i < ht*wd; i++)
//cout << weight[i] << endl;
free(A);
free(At);
free(AtA);
free(sAtA);
free(sAtL);
free(mBt);
free(mB);
free(mBtB);
free(result);
free(weight);
free(rgImage);
return 0;
}
}
int VignettingCorrect_16bit(Mat pImage)
{
ofstream myfile;
myfile.open("E:\Vignetting_image\vig_vector_16bit.txt");
myfile.open("E:\\Vignetting_image\\vig_vector_16bit.txt");
//pImage.convertTo(pImage, CV_16U);
int ht = pImage.rows;
int wd = pImage.cols;
int scanWd = pImage.step;
int nChannels = pImage.channels();
myfile << "ht: " << ht << endl;
myfile << "wd: " << wd << endl;
myfile << "scanWd: " << scanWd << endl;
myfile << "nChannels: " << nChannels << endl;
myfile << "**************************************" << endl;
double ratio = 1;
if (wd>75)
ratio = 75.0 / double(wd);
//resize the image
int sht = ht*ratio + 0.5;
int swd = wd*ratio + 0.5;
myfile << "sht: " << sht << endl;
myfile << "swd: " << swd << endl;
Mat pSmallImage;// = Mat(swd, sht, CV_16UC1, nChannels);
//convert from image to gray
Mat pGrayImage = Mat(swd, sht, CV_16UC1);
resize(pImage, pSmallImage, Size(swd, sht));
if (nChannels == 3)
{
pGrayImage = Mat(swd, sht, CV_16UC1, 1);
cvtColor(pSmallImage, pGrayImage, CV_BGR2GRAY);
}
else
{
pGrayImage = pSmallImage.clone();
}
imwrite("E:\\Vignetting_image\\pImage_input.png", pGrayImage);
// Vignetting correction
vector<double> vp;
int flag = VignettingCorrectionUsingRG_16bit((unsigned short*)pGrayImage.data, sht, swd, vp);
myfile << "vector values" << endl;
int nV = vp.size();
for (int i = 0; i < nV; i++)
{
myfile << vp[i] << endl;
}
imwrite("E:\\Vignetting_image\\pImage_before_flag.png", pImage);
if (flag == 0)
{
int nV = vp.size();
for (int i = 0; i < nV; i++)
{
vp[i] = exp(vp[i]);
}
//int nV = vp.size();
double maxVr = vp[0];
for (int i = 0; i < nV; i++)
{
vp[i] = vp[i] / maxVr;
//printf("%lf ", vp[i]);
}
int halfHt = ht*0.5;
int halfWd = wd*0.5;
int shalfHt = sht*0.5;
int shalfWd = swd*0.5;
//apply the vignetting correction
for (int j = 0; j < ht; j++)
for (int i = 0; i < wd; i++)
{
double cx = i - ht;
double cy = j - wd;
double radius = sqrt(cx*cx + cy*cy) + 0.50;
radius *= ratio;
//shd near interpolation
double vValue = 1;
int nR = int(radius);
if (nR == 0)
{
vValue = vp[0];
}
else if (nR < nV)
{
double dr = radius - nR;
vValue = vp[nR - 1] * (1 - dr) + vp[nR] * dr;
}
else
{
vValue = vp[nV - 1];
}
//radius = max(0, min(nV-1, radius));
//double scale = 1.0 / vp[radius];
double scale = 1.0 / vValue;
int r = (unsigned short)(pImage.data[j*scanWd + i * 3]);
int g = (unsigned short)(pImage.data[j*scanWd + i * 3 + 1]);
int b = (unsigned short)(pImage.data[j*scanWd + i * 3 + 2]);
r *= scale;
g *= scale;
b *= scale;
//pImage.data[(ht-j-1)*scanWd+i*3] = min(65535,r);
//pImage.data[(ht-j-1)*scanWd+i*3+1] = min(65535,g);
//pImage.data[(ht-j-1)*scanWd+i*3+2] = min(65535,b);
pImage.data[(j)*scanWd + i * 3] = min(65535, r);
pImage.data[(j)*scanWd + i * 3 + 1] = min(65535, g);
pImage.data[(j)*scanWd + i * 3 + 2] = min(65535, b);
}
imwrite("E:\\Vignetting_image\\pImage.png", pImage);
//Estimate the Correction for 16bit
Mat Estimate_temp = Mat(swd, sht, CV_16UC1, 1);
Mat Estimate = Mat(wd, ht, CV_16UC1, 1);
int flag1;
for (int i = 0; i < Estimate_temp.rows; i++)
{
unsigned short* data = (unsigned short*)Estimate_temp.data + i*Estimate_temp.step/2;
for (int j = 0; j < Estimate_temp.cols; j++)
{
int cx = i - shalfWd;
int cy = j - shalfHt;
int r = sqrt(double(cx*cx + cy*cy)) + 0.5;
if (r > 0 && r < nV + 1 && vp[r - 1] < 1)
{
data[j] = 65535 * vp[r - 1];
flag1 = 0;
}
else
{
data[j] = 65535;
flag1 = 1;
}
}
}
if (flag == 0)
{
imwrite("E:\\Vignetting_image\\output_3.png", pImage);
}
else
{
cout << "error" << endl;
}
resize(Estimate_temp, Estimate, Size(wd, ht));
imwrite("E:\\Vignetting_image\\estimate_vignet.png", Estimate);
}
myfile.close();
pGrayImage.release();
pSmallImage.release();
return 0;
}
}
int main()
{
//Read 16bit image
Mat img =
imread("E:\Vignetting_image\16_bit_image\input_image.png", CV_LOAD_IMAGE_ANYDEPTH);
imread("E:\\Vignetting_image\\16_bit_image\\input_image.png", CV_LOAD_IMAGE_ANYDEPTH);
if (VignettingCorrect_16bit(img) == 0)
{
//imwrite("Correction", img);
}
else
{
cout << "error" << endl;
}
return 0;
}
}