大家好,欢迎来到IT知识分享网。
1.积分图原理
I ( x , y ) = ∑ x ′ ⩽ x y ′ ⩽ y i ( x ′ , y ′ ) I(x,y)=\sum_{\begin{matrix} x’ \leqslant x \\\ y’ \leqslant y \\\ \end{matrix}} i(x’,y’) I(x,y)=x′⩽x y′⩽y ∑i(x′,y′)
积分图又称总和面积表(summed area table,简称SAT),是一个快速且有效的对一个网格的矩形子区域中计算和的数据结构和算法。
2. cv::integral
cv::integral 有三种重载形式:
//第一种重载形式 void integral( InputArray src, OutputArray sum, int sdepth = -1 ); //第二种重载形式 void integral( InputArray src, OutputArray sum, OutputArray sqsum, int sdepth = -1, int sqdepth = -1 ); //第三种重载形式 void integral( InputArray src, OutputArray sum, OutputArray sqsum, OutputArray tilted, int sdepth = -1, int sqdepth = -1 );
参数详解:
InputArray src:大小为 W × H W \times H W×H的输入图像。类型为8-bit或浮点型(32f或64f)。OutputArray sum:输出大小为 ( W + 1 ) × ( H + 1 ) (W+1) \times (H+1) (W+1)×(H+1)的积分图,类型为32-bit整型或浮点型(32f或64f)。
OutputArray sqsum:对像素值进行平方之后再计算得到的积分图,积分图大小是 ( W + 1 ) × ( H + 1 ) (W+1) \times (H+1) (W+1)×(H+1),类型为双精度浮点型(64f)。
OutputArray tilted:对原始图像旋转45度后再计算得到的积分图,积分图的大小依然是 ( W + 1 ) × ( H + 1 ) (W+1) \times (H+1) (W+1)×(H+1),类型和sum一样。
int sdepth = -1:sum和tilted的位图深度,可以是CV_32S、CV_32F或CV_64F。int sqdepth = -1:sqsum的位图深度,可以是CV_32F或CV_64F。
上图是一个例子。上图左是Rect(4,4,3,2)矩形内的积分计算,上图右是一个倾斜矩形Rect(5,1,2,3)内的积分计算。
3.代码测试:
Mat src = (Mat_<uchar>(2,3)<<1,2,3,4,5,6); for(int r =0 ; r<src.rows; r++) {
for(int c = 0 ; c<src.cols; c++) {
int i = src.ptr<uchar>(r)[c]; std::cout<<i<<" "; } std::cout<<std::endl; } /* 1 2 3 4 5 6 */ for(int r =0 ; r<src.rows; r++) {
for(int c = 0 ; c<src.cols; c++) {
int i = src.ptr<uchar>(r)[c]; std::cout<<i*i<<" "; } std::cout<<std::endl; } /* 1 4 9 16 25 36 */ Mat sumii = Mat::zeros(src.rows + 1, src.cols + 1, CV_32FC1); Mat sqsumii = Mat::zeros(src.rows + 1, src.cols + 1, CV_64FC1); Mat tilt = Mat::zeros(src.rows + 1, src.cols + 1, CV_32FC1); integral(src, sumii, sqsumii, tilt); for(int r =0 ; r<sumii.rows; r++) {
for(int c = 0 ; c<sumii.cols; c++) {
int i = sumii.ptr<int>(r)[c];//用float或double输出的数值不对 std::cout<<i<<" "; } std::cout<<std::endl; } /* 0 0 0 0 0 1 3 6 0 5 12 21 */ for(int r =0 ; r<sqsumii.rows; r++) {
for(int c = 0 ; c<sqsumii.cols; c++) {
double i = sqsumii.ptr<double>(r)[c]; std::cout<<i<<" "; } std::cout<<std::endl; } /* 0 0 0 0 0 1 5 14 0 17 46 91 */ for(int r =0 ; r<tilt.rows; r++) {
for(int c = 0 ; c<tilt.cols; c++) {
int i = tilt.ptr<int>(r)[c]; std::cout<<i<<" "; } std::cout<<std::endl; } /* 0 0 0 0 0 1 2 3 1 7 11 11 */
tilt 就是计算旋转45度后矩形的面积,比如:
积分二值化
主要步骤如下:
- 检查输入图像:首先,确保输入的图像不为空且是 8 位深度(即灰度图像或彩色图像)。
- 灰度转换:如果输入图像是彩色的,则转换为灰度图像,否则直接使用原图。
- 积分图像计算:通过
cv::integral计算输入图像的积分图像,这在之后的局部区域求和时使用。 - 设置参数:定义了局部窗口大小
S和阈值系数T,其中S是图像宽高的 1/8,T用于控制阈值的敏感度。 - 区域扫描与阈值计算:
- 对每个像素点,基于局部的
SxS窗口计算图像在该区域内的积分和(求和)。 - 然后通过对比像素值与该区域内像素值的均值(结合系数
T和输入的全局阈值thre)决定该像素是否置为 0 或 255(即黑或白)。
- 对每个像素点,基于局部的
- 输出结果:生成二值化图像
cv_dst。
这个自适应阈值方法比全局阈值更加灵活,特别适合处理光照不均匀的图像。
void threshold_integral(cv::Mat& cv_src, double thre, cv::Mat& cv_dst) {
// accept only char type matrices CV_Assert(!cv_src.empty()); CV_Assert(cv_src.depth() == CV_8U); cv::Mat cv_bin; if (cv_src.channels() != 1) {
cv::cvtColor(cv_src, cv_bin, cv::COLOR_BGR2GRAY); } else {
cv_bin = cv_src.clone(); } cv_dst = cv::Mat(cv_bin.size(), CV_8UC1, 1); // rows -> height -> y int nRows = cv_bin.rows; // cols -> width -> x int nCols = cv_bin.cols; // create the integral image cv::Mat sumMat; cv::integral(cv_bin, sumMat); CV_Assert(sumMat.depth() == CV_32S); CV_Assert(sizeof(int) == 4); int S = MAX(nRows, nCols) / 8; double T = 0.15; // perform thresholding int s2 = S / 2; int x1, y1, x2, y2, count, sum; // CV_Assert(sizeof(int) == 4); int* p_y1, * p_y2; uchar* p_inputMat, * p_outputMat; for (int i = 0; i < nRows; ++i) {
y1 = i - s2; y2 = i + s2; if (y1 < 0) {
y1 = 0; } if (y2 >= nRows) {
y2 = nRows - 1; } p_y1 = sumMat.ptr<int>(y1); p_y2 = sumMat.ptr<int>(y2); p_inputMat = cv_bin.ptr<uchar>(i); p_outputMat = cv_dst.ptr<uchar>(i); for (int j = 0; j < nCols; ++j) {
// set the SxS region x1 = j - s2; x2 = j + s2; if (x1 < 0) {
x1 = 0; } if (x2 >= nCols) {
x2 = nCols - 1; } count = (x2 - x1) * (y2 - y1); // I(x,y)=s(x2,y2)-s(x1,y2)-s(x2,y1)+s(x1,x1) sum = p_y2[x2] - p_y1[x2] - p_y2[x1] + p_y1[x1]; if ((int)(p_inputMat[j] * count) < (int)(sum * (1.0 - T) * thre)) p_outputMat[j] = 0; else p_outputMat[j] = 255; } } }
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/114712.html



