mirror of http://192.168.1.51:8099/lmh188/twain3
173 lines
4.6 KiB
C++
173 lines
4.6 KiB
C++
#include "ImageApplyTextureRemoval.h"
|
||
|
||
//交换对角线
|
||
void zero_to_center(cv::Mat& image, int colToCut, int rowToCut)
|
||
{
|
||
cv::Mat q1(image, cv::Rect(0, 0, colToCut, rowToCut));
|
||
cv::Mat q2(image, cv::Rect(colToCut, 0, colToCut, rowToCut));
|
||
cv::Mat q3(image, cv::Rect(0, rowToCut, colToCut, rowToCut));
|
||
cv::Mat q4(image, cv::Rect(colToCut, rowToCut, colToCut, rowToCut));
|
||
|
||
//第二象限和第四象限进行交换
|
||
cv::Mat tmpImg;
|
||
q1.copyTo(tmpImg);
|
||
q4.copyTo(q1);
|
||
tmpImg.copyTo(q4);
|
||
|
||
//第一象限和第三象限进行交换
|
||
q2.copyTo(tmpImg);
|
||
q3.copyTo(q2);
|
||
tmpImg.copyTo(q3);
|
||
}
|
||
|
||
//创建光谱
|
||
cv::Mat create_spectrum(cv::Mat* matArray, double scale = 1.5)
|
||
{
|
||
cv::Mat dst;
|
||
cv::magnitude(matArray[0], matArray[1], dst);
|
||
#if 1
|
||
cv::divide(dst, dst.cols * dst.rows, dst, scale);
|
||
//imshow("频谱", dst);
|
||
#else
|
||
dst += Scalar::all(1);
|
||
log(dst, dst);
|
||
normalize(dst, dst, 1, 0, CV_MINMAX);
|
||
#endif
|
||
|
||
#if 0
|
||
imshow("频谱", dst);
|
||
#endif
|
||
return dst;
|
||
}
|
||
|
||
//反傅里叶变换
|
||
void inverseFourierTransform(const cv::Mat& src, cv::Mat& dst)
|
||
{
|
||
cv::Mat complexIDFT;
|
||
cv::Mat matArray[2];
|
||
cv::idft(src, complexIDFT);
|
||
cv::split(complexIDFT, matArray);
|
||
cv::magnitude(matArray[0], matArray[1], dst);
|
||
cv::normalize(dst, dst, 0, 1, CV_MINMAX);
|
||
}
|
||
|
||
//制作陷波滤波器
|
||
cv::Mat createFilter(const cv::Mat& spectrum, int dilateSize, int erodeSize)
|
||
{
|
||
cv::Mat temp;
|
||
spectrum.convertTo(temp, CV_8UC1, 255);
|
||
cv::threshold(temp, temp, 0, 255, CV_THRESH_OTSU);
|
||
//imshow("二值化", temp);
|
||
|
||
cv::Mat element1 = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(dilateSize, dilateSize));
|
||
cv::Mat element2 = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(erodeSize, erodeSize));
|
||
cv::dilate(temp, temp, element1);
|
||
cv::erode(temp, temp, element2);
|
||
cv::floodFill(temp, cv::Point(temp.cols / 2, temp.rows / 2), cv::Scalar(0)); //漫水填充中心区域
|
||
cv::medianBlur(~temp, temp, 3); //中值滤波
|
||
//temp = ~temp;
|
||
//cv::imshow("二值化", temp);
|
||
|
||
//陷波滤波器复制
|
||
cv::Mat filter;
|
||
temp.convertTo(filter, CV_32FC1);
|
||
cv::normalize(filter, filter, 1, 0.01, CV_MINMAX);
|
||
std::vector<cv::Mat> mv;
|
||
mv.push_back(filter);
|
||
mv.push_back(filter);
|
||
cv::merge(mv, filter);
|
||
|
||
return filter;
|
||
}
|
||
|
||
void CImageApplyTextureRemoval::textureRemovalGray(cv::Mat& img)
|
||
{
|
||
//得到DFT的最佳尺寸(2的指数),以加速计算
|
||
cv::Mat paddedImg;
|
||
int m = cv::getOptimalDFTSize(img.rows);
|
||
int n = cv::getOptimalDFTSize(img.cols);
|
||
|
||
//填充图像的下端和右端
|
||
cv::copyMakeBorder(img, paddedImg, 0, m - img.rows, 0, n - img.cols,
|
||
cv::BORDER_CONSTANT, cv::Scalar::all(0));
|
||
|
||
//将填充的图像组成一个复数的二维数组(两个通道的Mat),用于DFT
|
||
cv::Mat matArray[] = { cv::Mat_<float>(paddedImg), cv::Mat::zeros(paddedImg.size(), CV_32F) };
|
||
cv::Mat complexInput, complexOutput;
|
||
cv::merge(matArray, 2, complexInput);
|
||
cv::dft(complexInput, complexOutput);
|
||
cv::split(complexOutput, matArray); //计算幅度谱(傅里叶谱)
|
||
|
||
//滤波
|
||
//将实部和虚部按照频谱图的方式换位
|
||
//低频在图像中心,用于滤波
|
||
zero_to_center(matArray[0], complexOutput.cols / 2, complexOutput.rows / 2);
|
||
zero_to_center(matArray[1], complexOutput.cols / 2, complexOutput.rows / 2);
|
||
cv::Mat spectrum = create_spectrum(matArray);
|
||
|
||
//创建滤波器
|
||
cv::Mat filter = createFilter(spectrum, m_dilateSize, m_erodeSize);
|
||
cv::merge(matArray, 2, complexOutput);
|
||
cv::multiply(complexOutput, filter, filter);
|
||
|
||
//IDFT得到滤波结果
|
||
cv::Size imgSize = img.size();
|
||
inverseFourierTransform(filter, img);
|
||
img = img(cv::Rect(cv::Point(0, 0), imgSize));
|
||
img *= 255;
|
||
img.convertTo(img, CV_8UC1);
|
||
}
|
||
|
||
CImageApplyTextureRemoval::CImageApplyTextureRemoval()
|
||
: CImageApply()
|
||
, m_dilateSize(5)
|
||
, m_erodeSize(3)
|
||
{
|
||
|
||
}
|
||
|
||
CImageApplyTextureRemoval::CImageApplyTextureRemoval(int dilateSize, int erodeSize)
|
||
: CImageApply()
|
||
, m_dilateSize(dilateSize)
|
||
, m_erodeSize(erodeSize)
|
||
{
|
||
|
||
}
|
||
|
||
CImageApplyTextureRemoval::~CImageApplyTextureRemoval()
|
||
{
|
||
|
||
}
|
||
|
||
void CImageApplyTextureRemoval::apply(cv::Mat &pDib, int side)
|
||
{
|
||
(void)side;
|
||
|
||
if (pDib.channels() == 1)
|
||
textureRemovalGray(pDib);
|
||
else
|
||
{
|
||
std::vector<cv::Mat> rgb(3);
|
||
cv::split(pDib, rgb);
|
||
for (cv::Mat& var : rgb)
|
||
textureRemovalGray(var);
|
||
cv::merge(rgb, pDib);
|
||
}
|
||
|
||
pDib *= 1.15;
|
||
}
|
||
|
||
void CImageApplyTextureRemoval::apply(std::vector<cv::Mat> &mats, bool isTwoSide)
|
||
{
|
||
(void)isTwoSide;
|
||
|
||
int i = 0;
|
||
for (cv::Mat& var : mats) {
|
||
if (i != 0 && isTwoSide == false)
|
||
break;
|
||
if (!var.empty())
|
||
apply(var, 0);
|
||
i++;
|
||
}
|
||
}
|