Derek Bradley & Gerhard Roth自适应二值化算法, Opencv实现

来源:互联网 发布:网络捕鱼游戏平台大全 编辑:程序博客网 时间:2024/06/07 02:26

算法介绍请参考: http://blog.csdn.net/qiaxi/article/details/49205135


二值化函数:


void BradleyThreshold(const cv::Mat& srcImage, cv::Mat& dstImage, int iRows, int iCols, double dPercentThres){// Safety checkif (srcImage.empty()){std::cout << "Empty matrix. Please check your input into QxBinarior::BradleyThreshold()" << std::endl << std::endl;return;}if (dPercentThres < -1){std::cout << "Percentage value can not be lhigher than 100% percent. Please check your input into QxBinarior::BradleyThreshold()" << std::endl << std::endl;return;}// Deal with even blocksizeif (iRows % 2 == 0)++iRows;if (iCols % 2 == 0)++iCols;// Deal with color imagecv::Mat grayImg;if (srcImage.type() == CV_8UC3)cv::cvtColor(srcImage, grayImg, CV_BGR2GRAY);elsegrayImg = srcImage;//--Generate integral image.int iRowAmount = grayImg.rows + 1; //Paddingint iColAmount = grayImg.cols + 1; //Paddingdouble* pIntegralImage = new double[iRowAmount * iColAmount];// Zero paddingfor (int iCol = 0; iCol < iColAmount; ++iCol)pIntegralImage[iCol] = 0.0;for (int iRow = 0; iRow < iRowAmount; ++iRow)pIntegralImage[iRow*iColAmount] = 0.0;bool bIsFirstRow = true;double dSum = 0.0;uchar* pCurrentRow = grayImg.ptr<uchar>(0);for (int iRow = 1; iRow < iRowAmount; ++iRow){bIsFirstRow = iRow == 1;pCurrentRow = grayImg.ptr<uchar>(iRow - 1);dSum = 0.0;for (int iCol = 1; iCol < iColAmount; ++iCol){dSum += pCurrentRow[iCol - 1];if (!bIsFirstRow)pIntegralImage[iRow*iColAmount + iCol] = dSum + pIntegralImage[(iRow - 1)*iColAmount + iCol];elsepIntegralImage[iRow*iColAmount + iCol] = dSum;}}//--Integral image generated.// Binarizationconst int iRowHalfRange = iRows / 2;const int iColHalfRange = iCols / 2;int iRowBegin = 0;int iRowEnd = 0;int iColBegin = 0;int iColEnd = 0;int iArea = 0;double dAverageVal = 0.0;dstImage.create(grayImg.size(), CV_8UC1);for (int iRow = 1; iRow < iRowAmount; ++iRow){uchar* pDstCurrentRow = dstImage.ptr<uchar>(iRow - 1);uchar* pSrcCurrentRow = grayImg.ptr<uchar>(iRow - 1);iRowBegin = iRow - iRowHalfRange - 1;iRowEnd = iRow + iRowHalfRange;if (iRowBegin < 0)iRowBegin = 0;if (iRowEnd >= iRowAmount)iRowEnd = iRowAmount - 1;for (int iCol = 1; iCol < iColAmount; ++iCol){iColBegin = iCol - iColHalfRange - 1;iColEnd = iCol + iColHalfRange;if (iColBegin < 0)iColBegin = 0;if (iColEnd >= iColAmount)iColEnd = iColAmount - 1;iArea = (iColEnd - iColBegin)*(iRowEnd - iRowBegin);dSum = pIntegralImage[iRowBegin*iColAmount + iColBegin] + pIntegralImage[iRowEnd*iColAmount + iColEnd]- pIntegralImage[iRowBegin*iColAmount + iColEnd] - pIntegralImage[iRowEnd*iColAmount + iColBegin];dAverageVal = dSum / iArea;pDstCurrentRow[iCol - 1] = pSrcCurrentRow[iCol - 1] > dAverageVal*(1 + dPercentThres) ? 255: 0;}}delete[] pIntegralImage;}


主函数:


#include <opencv2\core\core.hpp>#include <opencv2\imgproc\imgproc.hpp>#include <opencv2\highgui\highgui.hpp>#include "BradleyThreshold.h"using namespace cv;using namespace std;int main(){Mat matSrcImage = imread("E:\\Picture\\IMG\\191.jpg", CV_LOAD_IMAGE_COLOR);Mat matBinaryImage;BradleyThreshold(matSrcImage, matBinaryImage, 5, 5, 0.1);  //参数需根据不同图片设定imshow("Original Image", matSrcImage);imshow("Bianry Image", matBinaryImage);waitKey(0);return EXIT_SUCCESS;}

程序运行结果如下:

图1









--------------------------------------------------------------------------------------------------------

测试发现,这段代码的时间效率比Opencv自带函数adpativeThreshold()低30%-50%, 二值化表现各有千秋。

对于整体较明亮的图像,adaptiveThreshold()的表现优于以上代码。但是对于整体灰度值偏低的图片,上面那段代码的表现要优于

adaptiveThreshold(). 平均灰度越低,这种差异越明显。因此推荐大家对昏暗的图片采用Bradley与Roth提出的该算法,明亮图片采用adaptiveThreshold()函数。

adaptiveThreshold()与上述算法最大的区别在于: adaptiveThreshold()以灰度值的差值的绝对数值为参数区分前景与背景,该算法则使用差值与本身灰度值的百分比作为区分依据,因此后者在灰度值整体偏低的情况下更有区分性。大家也可以对这个算法做一些改进,比如在二值化操作之前先对更大邻域内的图像均值做一次评估,若均值偏高则使用绝对数值差异作为二值化依据;如果均值偏低则使用差值百分比参数作为区分依据。


0 0
原创粉丝点击