首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++ / OpenCV中局部阈值的实现

C++ / OpenCV中局部阈值的实现
EN

Stack Overflow用户
提问于 2015-01-14 17:03:42
回答 3查看 2.4K关注 0票数 3

我想实现一个局部阈值算法,我需要你的专业知识。

我的图像被调整为600x400,灰度。

关于本地化的基本思维过程:

  • 使用在每个像素处拍摄的9x9 ROI分割图像,并计算该区域的最大强度。
  • 创建一个9x9内核。 条件:

代码语言:javascript
复制
- if the center pixel of the mask is above 50% of the maximum intensity, set the center pixel true.(apply mask)

我的问题是:

  • 我该如何挑选我的内核/面具? 简历:Mat ROI;cv::Mat掩码(input.size(),CV_8UC1,cv::标量::all(0) );//创建0的掩码在第一次的const int核深度= 1;const int kernelsize = 9;cv::Mat内核= cv::Mat::one(核大小,核大小,CV_8UC1 );//获取ROI 9x9并为( double x= 9;x< input.cols -9;x++ ){ for( double y=9;y< input.rows -9;y++ ){ try{ double x_left =x- 4;double x_right =x+ 4;double y_up =y+ 4;double y_down =y- 4;double maxVal;double minVal;cv::Point锚(核大小/2,核大小/2);cv::Rect ROI = cv::Rect(x_left,y_down,9,9);cv::Mat ROI_Mat = input( ROI );// ROI的新矩阵::标量avgPixelIntensity =cv::ROI_Mat;//计算平均cv::minMaxLoc(ROI_Mat,&minVal,&maxVal);if( input.at(x,y) >= 0.5*maxVal){ cv::filter2D(输入,掩码,-1,内核,锚,0);}e.what()*更新后的代码:* applyLocalThresh( cv::Mat & src,cv::Mat & maxVal,minVal;cv::Mat输出;int上、下、左、右;int borderType = cv::BORDER_CONSTANT;cv:标量值;top = (int) (9);底部= (int) (9);左= (int) (9);右= (int) (9);输出= src;out = src;值= 0;cv::CopyMake边界(src,输出,上,下,左,右,右,borderType,值);(int y= 9;y< src.rows;y++) { for(int x= 9;x< src.cols;x ++) { cv::Mat ROI = src(cv::Rect(cv::Point(x-4,y-4),cv::Size(9,9));cv::minMaxLoc(ROI,&minVal,&maxVal);如果(src.at(cv::Point(x-4,y-4)) >= 0.6*maxVal){ out.at(cv::Point(x-4,y-4)) = 255;}out.at{ out.at(cv::Point(x-4,y-4));}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-01-15 22:43:45

经过进一步的思考,并找到了如何在编程中使用我的基本知识,我想出了这段代码,它不是最有效的,而是完成了工作。

我的方法的主要问题是什么?

  • 其中边界像素的主要问题之一和整个内核和掩码之间的索引操作引起了轻微的头痛。

我解决那件事的方法是什么?

  • 我的阈值说它需要一个相对高的亮度级别来设置真正的像素。因此,我在图像中填充了一些虚构的负像素,并使我的算法从原始图像的第一个像素开始。把结果保存在面具上。

结果:

  • 成功!

代码:

代码语言:javascript
复制
     double maxVal, minVal;
     cv::Mat output;
     int top, bottom, left , right;
     int borderType = cv::BORDER_CONSTANT;
     cv::Scalar value;
     top = (int) (4); bottom = (int) (4);
     left = (int) (4); right = (int) (4);
     output = src;
     out = src;
     value = 0;
     cv::copyMakeBorder(src,output,top,bottom,left,right,borderType,value);

for(int y = 4; y < output.rows - 4; y++) {

    for(int x = 4; x < output.cols - 4; x ++) {

        // apply local ROI

        cv::Mat ROI = output(cv::Rect(cv::Point(x-4,y-4),cv::Size(9,9)));
        cv::minMaxLoc(ROI,&minVal,&maxVal);    // extract max intensity values in the ROI

        if(src.at<uchar>(cv::Point(x-4,y-4)) >= 0.5*maxVal){    // apply local threshold w.r.t highest intensity level

            out.at<uchar>(cv::Point(x-4,y-4)) = 255;            // change pixel value in mask if true
        }else{
            out.at<uchar>(cv::Point(x-4,y-4)) = 0;

            }

        }
    }



}

它需要一些清理,我知道,但希望这将有助于其他人得到一些想法。

票数 2
EN

Stack Overflow用户

发布于 2015-01-15 07:19:52

您可以通过扩展,然后在OpenCV中进行比较来做到这一点;

代码语言:javascript
复制
im = load image here;
di = dilate im with a 9x9 kernel;
bw = im > (di * 0.5); // in OpenCV, pixels of bw are set to 255 or 0

用Matlab/Octave中的4x6图像和3x3内核来说明这一点的一个简单例子:

林=

代码语言:javascript
复制
 1     2     3     4     5     6
 2     3     4     5     6     7
 3     4     5     6     7     8
 4     5     6     7     8     9

迪=

代码语言:javascript
复制
 3     4     5     6     7     7
 4     5     6     7     8     8
 5     6     7     8     9     9
 5     6     7     8     9     9

th = di * .5

th =

代码语言:javascript
复制
1.5000    2.0000    2.5000    3.0000    3.5000    3.5000
2.0000    2.5000    3.0000    3.5000    4.0000    4.0000
2.5000    3.0000    3.5000    4.0000    4.5000    4.5000
2.5000    3.0000    3.5000    4.0000    4.5000    4.5000

bw = im > th

bw =

代码语言:javascript
复制
 0     0     1     1     1     1
 0     1     1     1     1     1
 1     1     1     1     1     1
 1     1     1     1     1     1
票数 3
EN

Stack Overflow用户

发布于 2015-01-14 22:55:13

我恐怕这种做法并不完全正确。让我解释一下:对于涉及内核的操作,必须小心地将放在要转换的像素上的内核的中心。那是因为3x3,5x5,7x7,9x9 (.)内核只计算图像中的(一个像素)的值,这个值位于内核的中心0,0。

如果您考虑如何计算图像的第一个像素的值,9x9内核的中心将放置在坐标0,0上。这意味着内核的3/4将放置在负坐标,即指不存在的像素的坐标:

代码语言:javascript
复制
 [-4,-4][-3,-4][-2,-4][-1,-4][ 0,-4][ 1,-4][ 2,-4][ 3,-4][ 4,-4]
 [-4,-3][-3,-3][-2,-3][-1,-3][ 0,-3][ 1,-3][ 2,-3][ 3,-3][ 4,-3]
 [-4,-2][-3,-2][-2,-2][-1,-2][ 0,-2][ 1,-2][ 2,-2][ 3,-2][ 4,-2]
 [-4,-1][-3,-1][-2,-1][-1,-1][ 0,-1][ 1,-1][ 2,-1][ 3,-1][ 4,-1]
 [-4, 0][-3, 0][-2, 0][-1, 0][ 0, 0][ 1, 0][ 2, 0][ 3, 0][ 4, 0]
 [-4, 1][-3, 1][-2, 1][-1, 1][ 0, 1][ 1, 1][ 2, 1][ 3, 1][ 4, 1]
 [-4, 2][-3, 2][-2, 2][-1, 2][ 0, 2][ 1, 2][ 2, 2][ 3, 2][ 4, 2]
 [-4, 3][-3, 3][-2, 3][-1, 3][ 0, 3][ 1, 3][ 2, 3][ 3, 3][ 4, 3]
 [-4, 4][-3, 4][-2, 4][-1, 4][ 0, 4][ 1, 4][ 2, 4][ 3, 4][ 4, 4]

--这总是发生在靠近图像边界的像素上。因此,对于第一个像素的计算,我们必须将计算限制在内核的1/4,这是指目标图像中的有效坐标:

代码语言:javascript
复制
 [     ][     ][     ][     ][     ][     ][     ][     ][     ]
 [     ][     ][     ][     ][     ][     ][     ][     ][     ]
 [     ][     ][     ][     ][     ][     ][     ][     ][     ]
 [     ][     ][     ][     ][     ][     ][     ][     ][     ]
 [     ][     ][     ][     ][ 0, 0][ 1, 0][ 2, 0][ 3, 0][ 4, 0]
 [     ][     ][     ][     ][ 0, 1][ 1, 1][ 2, 1][ 3, 1][ 4, 1]
 [     ][     ][     ][     ][ 0, 2][ 1, 2][ 2, 2][ 3, 2][ 4, 2]
 [     ][     ][     ][     ][ 0, 3][ 1, 3][ 2, 3][ 3, 3][ 4, 3]
 [     ][     ][     ][     ][ 0, 4][ 1, 4][ 2, 4][ 3, 4][ 4, 4]

因此,当前方法的问题是,在某个时候,您将设置一个具有负坐标的ROI,当执行这些指令时,您将看到一个很好的崩溃:

代码语言:javascript
复制
cv::Mat ROI_Mat = input(ROI);  // crash 

解决方案是不使用ROI,只需自己实现该算法。我只是无法看到这种自定义计算与cv::filter2D()一起工作。以下是一些帮助你开始工作的小东西:

代码语言:javascript
复制
void local_threshold(const cv::Mat& input, cv::Mat& output)
{
    if (input.channels() != 1)
    {
        std::cout << "local_threshold !!! input image must be single channel" << std::endl;
        return;
    }

    output = cv::Mat(input.rows, input.cols, CV_8UC1);
    double min_val = 0, max_val = 0;

    for (int i = 0; i < input.rows; i++)
        for (int j = 0; j < input.cols; j++)
        {
            cv::Mat kernel = Mat::zeros(9, 9, output.type());

            // Implement logic to fill the 9x9 kernel with
            // values from the input Mat, respecting boundaries.

            cv::Scalar avg_intensity = cv::mean(kernel);
            cv::minMaxLoc(kernel, &min_val,&max_val);

            if (input.at<uchar>(i,j) > (max_val / 2))
                output.at<unsigned char>(i,j) = 255;
            else
                output.at<unsigned char>(i,j) = 0;
        }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27948473

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档