You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
260 lines
7.0 KiB
260 lines
7.0 KiB
#include "opencv2/structured_light/slmono_utils.hpp" |
|
|
|
namespace cv{ |
|
namespace structured_light{ |
|
|
|
//quadrand swapping for FFT |
|
void circshift(OutputArray out, InputArray in, int xdim, int ydim, bool isFftshift = true) { |
|
|
|
Mat in_ = in.getMat(); |
|
Mat& out_ = *(Mat*) out.getObj(); |
|
|
|
if (isFftshift) { |
|
int xshift = (xdim / 2); |
|
int yshift = (ydim / 2); |
|
|
|
for (int i = 0; i < xdim; i++) { |
|
int ii = (i + xshift) % xdim; |
|
for (int j = 0; j < ydim; j++) { |
|
int jj = (j + yshift) % ydim; |
|
out_.at<float>(ii * ydim + jj) = in_.at<float>(i * ydim + j); |
|
} |
|
} |
|
} |
|
else { |
|
int xshift = ((xdim + 1) / 2); |
|
int yshift = ((ydim + 1) / 2); |
|
|
|
for (int i = 0; i < xdim; i++) { |
|
int ii = (i + xshift) % xdim; |
|
for (int j = 0; j < ydim; j++) { |
|
int jj = (j + yshift) % ydim; |
|
out_.at<float>(ii * ydim + jj) = in_.at<float>(i * ydim + j); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
void createGrid(OutputArray output, Size size) { |
|
auto gridX = Mat(size, CV_32FC1); |
|
auto gridY = Mat(size, CV_32FC1); |
|
|
|
for (auto i = 0; i < size.height; i++) { |
|
for (auto j = 0; j < size.width; j++) { |
|
gridX.at<float>(i, j) = float(j + 1); |
|
gridY.at<float>(i, j) = float(i + 1); |
|
} |
|
} |
|
multiply(gridX, gridX, gridX); |
|
multiply(gridY, gridY, gridY); |
|
|
|
add(gridX, gridY, output); |
|
} |
|
|
|
void wrapSin(InputArray img, OutputArray out) { |
|
|
|
Mat img_ = img.getMat(); |
|
Mat& out_ = *(Mat*) out.getObj(); |
|
out_ = Mat(img_.rows, img_.cols, CV_32FC1); |
|
|
|
for (auto i = 0; i < img_.rows; i++) { |
|
for (auto j = 0; j < img_.cols; j++) { |
|
float x = img_.at<float>(i, j); |
|
while (abs(x) >= M_PI_2) { |
|
x += ((x > 0) - (x < 0)) * (float(M_PI) - 2 * abs(x)); |
|
} |
|
out_.at<float>(i, j) = x; |
|
} |
|
} |
|
} |
|
|
|
void wrapCos(InputArray img, OutputArray out) { |
|
|
|
Mat img_ = img.getMat(); |
|
Mat& out_ = *(Mat*) out.getObj(); |
|
out_ = Mat(img_.rows, img_.cols, CV_32FC1); |
|
|
|
for (auto i = 0; i < img_.rows; i++) { |
|
for (auto j = 0; j < img_.cols; j++) { |
|
float x = img_.at<float>(i, j) - (float)M_PI_2; |
|
while (abs(x) > M_PI_2) { |
|
x += ((x > 0) - (x < 0)) * ((float)M_PI - 2 * abs(x)); |
|
} |
|
out_.at<float>(i, j) = -x; |
|
} |
|
} |
|
} |
|
|
|
void computeAtanDiff(InputOutputArrayOfArrays src, OutputArray dst) { |
|
|
|
std::vector<Mat>& src_ = *( std::vector<Mat>* ) src.getObj(); |
|
|
|
Mat& dst_ = *(Mat*) dst.getObj(); |
|
|
|
for (int i = 0; i < src_[0].rows; i++) { |
|
for (int j = 0; j < src_[0].cols; j++) { |
|
float x = src_[3].at<float>(i, j) - src_[1].at<float>(i, j); |
|
float y = src_[0].at<float>(i, j) - src_[2].at<float>(i, j); |
|
dst_.at<float>(i, j) = std::atan2(x, y); |
|
} |
|
} |
|
} |
|
|
|
void Laplacian(InputArray img, InputArray grid, OutputArray out, int flag = 0) { |
|
|
|
Mat& img_ = *(Mat*) img.getObj(); |
|
Mat& out_ = *(Mat*) out.getObj(); |
|
|
|
if (flag == 0){ |
|
dct(img, out_); |
|
multiply(out_, grid, out_); |
|
dct(out_, out_, DCT_INVERSE); |
|
out_ = out_ * (-4 * M_PI * M_PI / (img_.rows * img_.cols)); |
|
} |
|
else if (flag == 1) |
|
{ |
|
dct(img, out_); |
|
divide(out_, grid, out_); |
|
dct(out_, out_, DCT_INVERSE); |
|
out_ = out_ * (-img_.rows * img_.cols) / (4 * M_PI * M_PI); |
|
} |
|
|
|
} |
|
|
|
void computeDelta(InputArray img, InputArray grid, OutputArray out) { |
|
|
|
Mat x1, x2; |
|
Mat img_sin, img_cos; |
|
|
|
wrapSin(img, img_sin); |
|
wrapCos(img, img_cos); |
|
|
|
Mat laplacian1, laplacian2; |
|
|
|
Laplacian(img_sin, grid, laplacian1); |
|
Laplacian(img_cos, grid, laplacian2); |
|
|
|
multiply(img_cos, laplacian1, x1); |
|
multiply(img_sin, laplacian2, x2); |
|
subtract(x1, x2, out); |
|
} |
|
|
|
|
|
void unwrapPCG(InputArray img, OutputArray out, Size imgSize) { |
|
|
|
Mat g_laplacian; |
|
Mat phase1; |
|
Mat error, k1, k2, phase2; |
|
Mat phiError; |
|
|
|
createGrid(g_laplacian, imgSize); |
|
computeDelta(img, g_laplacian, phase1); |
|
Laplacian(phase1, g_laplacian, phase1, 1); |
|
|
|
subtract(phase1, img, k1); |
|
k1 *= 0.5 / M_PI; |
|
abs(k1); |
|
k1 *= 2 * M_PI; |
|
add(img, k1, out); |
|
|
|
for (auto i = 0; i < 0; i++) { |
|
subtract(phase2, phase1, error); |
|
computeDelta(error, g_laplacian, phiError); |
|
Laplacian(phiError, g_laplacian, phiError, 1); |
|
|
|
add(phase1, phiError, phase1); |
|
subtract(phase1, img, k2); |
|
k2 *= 0.5 / M_PI; |
|
abs(k2); |
|
k2 *= 2 * M_PI; |
|
add(img, k2, out); |
|
k2.copyTo(k1); |
|
} |
|
} |
|
|
|
void unwrapTPU(InputArray phase1, InputArray phase2, OutputArray out, int scale) { |
|
|
|
Mat& phase1_ = *(Mat*) phase1.getObj(); |
|
Mat& phase2_ = *(Mat*) phase2.getObj(); |
|
|
|
phase1_.convertTo(phase1_, phase1_.type(), scale); |
|
subtract(phase1_, phase2_, phase1_); |
|
phase1_.convertTo(phase1_, phase1_.type(), 0.5f / CV_PI); |
|
abs(phase1_); |
|
phase1_.convertTo(phase1_, phase1_.type(), 2 * CV_PI); |
|
add(phase1_, phase2_, out); |
|
} |
|
|
|
void fft2(InputArray in, OutputArray complexI) { |
|
|
|
Mat in_ = in.getMat(); |
|
Mat& complexI_ = *(Mat*) complexI.getObj(); |
|
|
|
Mat padded; |
|
int m = getOptimalDFTSize(in_.rows); |
|
int n = getOptimalDFTSize(in_.cols); |
|
copyMakeBorder(in, padded, 0, m - in.rows, 0, n - in.cols, |
|
BORDER_CONSTANT, Scalar::all(0)); |
|
|
|
Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)}; |
|
merge(planes, 2, complexI_); |
|
dft(complexI_, complexI_); |
|
} |
|
|
|
void lowPassFilter(InputArray image, OutputArray out, int filterSize) { |
|
Mat& image_ = *(Mat*) image.getObj(); |
|
int rows = image_.rows; |
|
int cols = image_.cols; |
|
|
|
Mat greyMat; |
|
cvtColor(image, greyMat, COLOR_BGR2GRAY); |
|
Mat result; |
|
fft2(greyMat, result); |
|
Mat matrix_(Size(rows, cols), CV_64FC1); |
|
circshift(matrix_, result, result.rows, result.cols, true); |
|
|
|
|
|
Mat lowPass(Size(rows, cols), CV_64FC1, Scalar(0)); |
|
|
|
lowPass(Rect_<int>((int)(0.5*rows-filterSize), (int)(0.5 * cols - filterSize), |
|
(int)(0.5*rows+filterSize), (int)(0.5 * cols + filterSize))) = 1; |
|
|
|
Mat pass = matrix_.mul(lowPass); |
|
|
|
Mat J1(Size(rows, cols), CV_64FC1); |
|
circshift(J1, pass, rows, cols, false); |
|
|
|
idft(J1, out); |
|
|
|
} |
|
|
|
void highPassFilter(InputArray image, OutputArray out, int filterSize) { |
|
|
|
Mat& image_ = *(Mat*) image.getObj(); |
|
int rows = image_.rows; |
|
int cols = image_.cols; |
|
|
|
Mat greyMat; |
|
cvtColor(image, greyMat, COLOR_BGR2GRAY); |
|
Mat result; |
|
fft2(greyMat, result); |
|
Mat matrix_(Size(rows, cols), CV_64FC1); |
|
circshift(matrix_, result, result.rows, result.cols, true); |
|
|
|
Mat highPass(Size(rows, cols), CV_64FC1, Scalar(1)); |
|
|
|
highPass(Rect_<int>((int)(0.5*rows-filterSize), (int)(0.5 * cols - filterSize), |
|
(int)(0.5*rows+filterSize), (int)(0.5 * cols + filterSize))) = 0; |
|
|
|
Mat pass = matrix_.mul(highPass); |
|
|
|
Mat filter(Size(rows, cols), CV_64FC1); |
|
circshift(filter, pass, rows, cols, false); |
|
|
|
idft(filter, out); |
|
} |
|
|
|
|
|
} |
|
} |