在OpenCV中选择最高强度的像素

8

有人能帮我在OpenCV中找到灰度图像中最亮的前1%(或说前100个像素)的像素及它们的位置吗?因为cvMinMaxLoc()只提供最亮像素的位置。

非常感谢任何帮助。

5个回答

2
这是一个简单但低效/愚蠢的做法:
for i=1:100
  get brightest pixel using cvMinMaxLoc 
  store location
  set it to a value of zero
end

如果您不关心效率,这应该可以工作。

您还应该检查cvInRangeS以找到定义低和高阈值的其他相似值像素。


1

基于其他帖子的一些想法的C++版本:

// filter the brightest n pixels from a grayscale img, return a new mat
cv::Mat filter_brightest( const cv::Mat& src, int n ) {

    CV_Assert( src.channels() == 1 );
    CV_Assert( src.type() == CV_8UC1 );

    cv::Mat result={};

    // simple histogram
    std::vector<int> histogram(256,0); 
    for(int i=0; i< int(src.rows*src.cols); ++i) 
        histogram[src.at<uchar>(i)]++;

    // find max threshold value (pixels from [0-max_threshold] will be removed)
    int max_threshold = (int)histogram.size() - 1;
    for ( ; max_threshold >= 0 && n > 0; --max_threshold ) {
        n -= histogram[max_threshold];
    }

    if ( max_threshold < 0 )  // nothing to do
        src.copyTo(result);
    else     
        cv::threshold(src, result, max_threshold, 0., cv::THRESH_TOZERO);

    return result;
}

用法示例:获取前1%
auto top1 = filter_brightest( img, int((img.rows*img.cols) * .01) );

1

你需要从直方图中计算出亮度阈值。然后遍历像素以获取那些足够亮来满足阈值的位置。下面的程序是将阈值应用于图像并显示结果以进行演示:

#!/usr/bin/env python3

import sys
import cv2
import matplotlib.pyplot as plt

if __name__ == '__main__':
    if len(sys.argv) != 2 or any(s in sys.argv for s in ['-h', '--help', '-?']):
        print('usage: {} <img>'.format(sys.argv[0]))
        exit()
    img = cv2.imread(sys.argv[1], cv2.IMREAD_GRAYSCALE)
    hi_percentage = 0.01 # we want we the hi_percentage brightest pixels
    # * histogram
    hist = cv2.calcHist([img], [0], None, [256], [0, 256]).flatten()
    # * find brightness threshold
    # here: highest thresh for including at least hi_percentage image pixels,
    #       maybe you want to modify it for lowest threshold with for including
    #       at most hi_percentage pixels
    total_count = img.shape[0] * img.shape[1]  # height * width
    target_count = hi_percentage * total_count # bright pixels we look for
    summed = 0
    for i in range(255, 0, -1):
        summed += int(hist[i])
        if target_count <= summed:
            hi_thresh = i
            break
    else:
        hi_thresh = 0
    # * apply threshold & display result for demonstration purposes:
    filtered_img = cv2.threshold(img, hi_thresh, 0, cv2.THRESH_TOZERO)[1]
    plt.subplot(121)
    plt.imshow(img, cmap='gray')
    plt.subplot(122)
    plt.imshow(filtered_img, cmap='gray')
    plt.axis('off')
    plt.tight_layout()
    plt.show()

0

最合理的方法是迭代整个图片,然后获取像素的最大值最小值。然后选择一个阈值,该阈值将给您所需的百分比(在您的情况下为1%)。之后再次迭代并保存每个像素的ij坐标超过给定的阈值。这样,您只需要迭代矩阵两次而不是100次(或1%的像素次数),就可以选择最亮的像素并删除它。

OpenCV mats是多维数组。灰度图像是具有从0到255的值的二维数组。您可以像这样遍历矩阵。 for(int i=0;i < mat.height();i++) for(int j=0;j < mat.width();j++) mat[i][j];


0

哦,我的错。我以为你的意思是它会给出所有具有(相同)最亮强度的像素。我不知道...你希望得到什么格式的返回?一个x,y坐标列表?为什么不像我建议的那样使用二进制阈值,然后随意循环图像?实际上,如果你要循环它,你可以同时自己做阈值处理。 - mpen
是的...找到所有最亮像素的(x,y)坐标...有点像排序,但是需要考虑位置... - Dark Knight
可以把那个部分发给我吗?我的邮箱是ajith.srao@gmail.com - Dark Knight
你真的想让我发送一个for循环吗?认真的?for(int y=0;y<height;++y){for(int x=0; x<width;++x){if(image[x][y]>threshold){do_something_with_coords(x,y);}}} - mpen
哈哈... :) 我以为你会使用像 minmaxLoc 这样的函数... 不管怎样,我们会看到的,谢谢。 - Dark Knight
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接