我想对低质量的图像进行二值化处理,发现使用Sauvola方法,NiBlack方法等全局和局部二值化技术的现有解决方案或程序使用得并不多。
我确实找到了一些关于更好的方法的好论文,例如论文中给出的方法:
1)http://www.ski.org/sites/default/files/publications/wacv11-display-reader.pdf#cite.adap-binar
2)https://www.jstage.jst.go.jp/article/elex/1/16/1_16_501/_pdf
但是我之前没有从事图像处理工作,所以我想知道如何继续实现它以及实现这些算法需要哪些知识
最佳答案
我在大约10分钟内实现了第一张纸的二值化(比处理第二张图像所需的时间更少)-不保证它是正确的,最好自己看一下公式:
int main()
{
//cv::Mat input = cv::imread("../inputData/Lenna.png");
cv::Mat input = cv::imread("../inputData/LongLineColor.jpg");
cv::Mat gray;
cv::cvtColor(input,gray,CV_BGR2GRAY);
cv::Mat binaryImage = cv::Mat::zeros(gray.rows, gray.cols, CV_8UC1);
// binarization:
// TODO: adjust to your application:
int smallWindowSize = 17; // suggested by the paper
int bigWindowSize = 35; // suggested by the paper
// TODO: adjust to your application
double minTau = 10 ;
// create roi relative to (0,0)
cv::Rect roiTemplate1 = cv::Rect(-smallWindowSize/2,-smallWindowSize/2, smallWindowSize, smallWindowSize);
cv::Rect roiTemplate2 = cv::Rect(-bigWindowSize/2,-bigWindowSize/2, bigWindowSize, bigWindowSize);
cv::Rect imgROI = cv::Rect(0,0, gray.cols, gray.rows);
for(int y=0; y<gray.rows; ++y)
{
std::cout << y << std::endl;
for(int x=0; x<gray.cols; ++x)
{
double pixelThreshold = 255;
// small roi
cv::Rect cROIs = roiTemplate1 + cv::Point(x,y);
// test whether ROI is inside the image. Reduce otherwise:
cROIs = cROIs & imgROI;
if(cROIs.width == 0 || cROIs.height == 0)
continue; // ignore this pixel
// large roi
cv::Rect cROIl = roiTemplate2 + cv::Point(x,y);
cROIl = cROIl & imgROI;
if(cROIl.width == 0 || cROIl.height == 0)
continue; // ignore this pixel
cv::Mat subSmall = gray(cROIs);
cv::Mat subLarge = gray(cROIl);
// evaluate subimages:
// standard deviations
double stdDevS =0;
double stdDevL =0;
// mean value
double meanS =0;
double minL =DBL_MAX;
double meanL =0;
// mean of small region
for(int j=0; j<subSmall.rows; ++j)
for(int i=0; i<subSmall.cols; ++i)
{
meanS += subSmall.at<unsigned char>(j,i);
}
meanS = meanS/ (double)(subSmall.cols*subSmall.rows);
// stddev of small region
for(int j=0; j<subSmall.rows; ++j)
for(int i=0; i<subSmall.cols; ++i)
{
double diff = subSmall.at<unsigned char>(j,i) - meanS;
stdDevS += diff*diff;
}
stdDevS = sqrt(stdDevS/(double)(subSmall.cols*subSmall.rows));
// mean and min of large region
for(int j=0; j<subLarge.rows; ++j)
for(int i=0; i<subLarge.cols; ++i)
{
if(subLarge.at<unsigned char>(j,i) < minL)
{
minL = subLarge.at<unsigned char>(j,i);
meanL += subLarge.at<unsigned char>(j,i);
}
}
meanL = meanL/ (double)(subLarge.cols*subLarge.rows);
// stddef of large region
for(int j=0; j<subLarge.rows; ++j)
for(int i=0; i<subLarge.cols; ++i)
{
double diff = subLarge.at<unsigned char>(j,i) - meanL;
stdDevL += diff*diff;
}
stdDevL = sqrt(stdDevL/(double)(subLarge.cols*subLarge.rows));
// formula (2)
double tau = ((meanS - minL) * (1-stdDevS/stdDevL))/2.0;
// minimum
if(tau < minTau) tau = minTau;
// formula (1)
double Threshold = meanS - tau;
// for debugging:
/*
std::cout << " meanS:" << meanS << std::endl;
std::cout << " std S:" << stdDevS << std::endl;
std::cout << " min L:" << minL << std::endl;
std::cout << " meanL:" << meanL << std::endl;
std::cout << " std L:" << stdDevL << std::endl;
std::cout << " threshold: " << Threshold << std::endl;
*/
unsigned char pixelVal = gray.at<unsigned char>(y,x);
if(pixelVal >= Threshold)
binaryImage.at<unsigned char>(y,x) = 255;
else
binaryImage.at<unsigned char>(y,x) = 0;
}
}
cv::imshow("input", input);
cv::imshow("binary", binaryImage);
//cv::imwrite("../outputData/binaryCustom.png", binaryImage);
cv::waitKey(0);
return 0;
}
给我这些结果:
和
它很慢,但是根本没有优化或封装;)
结果真是不好,恕我直言。可能您必须将windowSizes调整为您的应用程序/任务/ objectSize
关于opencv - opencv中使用更新算法的图像二值化,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33229175/