Выбор пикселей с наибольшей интенсивностью в OpenCV

Может ли кто-нибудь помочь мне узнать 1% (или, скажем, 100 лучших пикселей) самых ярких пикселей с их расположением на сером изображении в opencv. потому что cvMinMaxLoc() дает местоположение только самого яркого пикселя.

Любая помощь приветствуется.


person Dark Knight    schedule 06.09.2010    source источник


Ответы (5)


это простой, но неэффективный/глупый способ сделать это:

for i=1:100
  get brightest pixel using cvMinMaxLoc 
  store location
  set it to a value of zero
end

если вы не возражаете против эффективности, это должно сработать.

вы также должны проверить cvInRangeS, чтобы найти другие пиксели с похожими значениями, определяющими низкие и высокие пороги.

person dnul    schedule 06.09.2010

Вам нужно вычислить порог яркости из гистограммы. Затем вы перебираете пиксели, чтобы получить те позиции, которые достаточно яркие, чтобы удовлетворить порог. Вместо этого приведенная ниже программа применяет порог к изображению и отображает результат в демонстрационных целях:

#!/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()
person Lars    schedule 11.04.2017

Версия 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) );
person Tom    schedule 26.01.2020

Вместо этого попробуйте использовать cvThreshold.

person mpen    schedule 06.09.2010
comment
@Mark: пороговое значение не помогает, нужно узнать самые яркие пиксели и их расположение. - person Dark Knight; 06.09.2010
comment
Как это не помогает? Сначала установите пороговое значение, чтобы увеличить их интенсивность до максимума, а затем используйте свой cvMinMaxLoc, чтобы определить, где они находятся. - person mpen; 06.09.2010
comment
cvMinMaxLoc дает местоположение только одного самого яркого пикселя, как я могу узнать другое местоположение с такой же интенсивностью? - person Dark Knight; 06.09.2010
comment
О.. мой плохой. Я думал, вы имели в виду, что он дает все пиксели с (одинаковой) самой яркой интенсивностью. Я не знаю... какой формат вы надеетесь вернуть? Список координат x, y? Почему бы просто не использовать двоичный порог, как я предложил, а затем циклически перебирать изображение, как вам заблагорассудится? На самом деле, если вы собираетесь зациклить его, вы можете сделать пороговое значение самостоятельно в то же время. - person mpen; 06.09.2010
comment
да... нахождение (x,y)координат всех этих самых ярких пикселей... своего рода сортировка, но с расположением... - person Dark Knight; 06.09.2010
comment
я почти уверен, что просто зациклил это в своем проекте. - person mpen; 06.09.2010
comment
k..можете выслать мне эту часть? аджит.срао@gmail.com - person Dark Knight; 06.09.2010
comment
Вы действительно хотите, чтобы я отправил вам цикл 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);}}} - person mpen; 06.09.2010
comment
ха-ха...:) я думал, ты используешь какую-нибудь fn, например, minmaxLoc... в любом случае увидишь, ты - person Dark Knight; 06.09.2010

Что ж, самый логичный способ — перебрать всю картинку, а затем получить значения max и min пикселей. Затем выберите порог, который даст вам желаемый процент (1% в вашем случае). После этого повторите еще раз и сохраните координаты i и j каждого пикселя выше заданного порога. Таким образом, вы будете перебирать матрицу только два раза вместо 100 (или 1% раз от пикселей), выбирая самые яркие и удаляя их.

Маты OpenCV представляют собой многомерные массивы. Серое изображение представляет собой двумерный массив со значениями от 0 до 255. Вы можете перебирать матрицу следующим образом. for(int i=0;i < mat.height();i++) for(int j=0;j < mat.width();j++) mat[i][j];

person Petar Velev    schedule 20.06.2017