Как получить координату ярких или темных пикселей? OpenCV

Я пытаюсь получить координату белого и черного пикселей из бинарного изображения, чтобы получить ROI изображения и изменить значения пикселей. Любая функция, которую я могу вызвать?

Это исходное изображение

После этого он будет пороговым по методу OTSU. Результат: Рисунок 8.7

Я хочу получить результат рисунка 8.8 из рисунка 8.7 (извините за изображение, я уже пытался его повернуть, но оно все еще выглядит так). Есть ли какой-нибудь метод?

Вот пороговая ссылка на изображение. https://i.imgur.com/9EXmHN0.png

После этого я смогу получить свой ROI.


person user3396218    schedule 19.03.2014    source источник
comment
не совсем то, что на рис. 8.8, но вы можете попробовать большой медианный фильтр на изображении с порогом! Чтобы улучшить то, что показано на рис. 8.8, я бы попытался разделить ваше изображение на квадратные ячейки размером x², затем подсчитать в каждой ячейке, есть ли больше белых или черных пикселей, и раскрасить всю ячейку (в изображении маски/рои) в этом цвет.   -  person Micka    schedule 19.03.2014
comment
кстати: если вы предоставите образец изображения с пороговым значением, можно даже попытаться реализовать это для вас;)   -  person Micka    schedule 19.03.2014
comment
@Micka, я собираюсь реализовать маску 16x26 пикселей и вычислить процент белых пикселей. Но это может занять некоторое время. Кстати, изображение 320x480. Вот изображение! Буду признателен, если вы готовы помочь. Благодарность! кстати пороговое значение от OTSU = 58. i.imgur.com/9EXmHN0.png   -  person user3396218    schedule 19.03.2014


Ответы (3)


Ну вот:

Разделите изображение на блоки/ячейки и вычислите соотношение/процент белого/черного пикселя и окрасьте весь блок в маске изображения в желаемый цвет.

int main()
{
// load your real image here
cv::Mat img = cv::imread("fingerprint.png", CV_LOAD_IMAGE_GRAYSCALE);


// after thresholding: all pixel 255 or 0
cv::Mat thres = img > 0;    // input image was thresholded already...
//cv::threshold(img,thres,58,255,CV_THRESH_OTSU);   // if original input, use your OTSU (remark: have to convert to grayscale first?)

cv::Mat mask = thres.clone();
mask = 100; // set it to gray to see at the end whether all blocks were performed and painted

//float minRatio = 0.5f;
float minRatio = 0.3f;
//float minRatio = 0.1f;    // ratio of white pixel within a block to accept as a filled block

// size of a single block:
cv::Size block(16,26);

// count pixel in each block and decide whether the block is white or black:
for(int j=0; j<img.rows; j+=block.height)
    for(int i=0; i<img.cols; i+=block.width)
    {
        // current block:
        cv::Rect currentBlock(i, j, block.width, block.height);

        // pixel counter
        unsigned int cWhite = 0;
        unsigned int cBlack = 0;
        // iterate through whole block and count pixels
        for(int y=currentBlock.y; y<currentBlock.y+currentBlock.height; ++y)
            for(int x=currentBlock.x; x<currentBlock.x+currentBlock.height; ++x)
            {
                // care for blocks that don't fit into the image. If known imagesize and block sizes fit exactly, this may be removed
                if((y < img.rows)&&(x < img.cols))
                {
                    if(thres.at<unsigned char>(y,x) == 255) cWhite++;
                    else cBlack++;
                }
            }

        // compute block color from ratio
        unsigned char blockColor = 0;
        if((float)cWhite/(float)(cBlack+cWhite) > minRatio) blockColor = 255;

        // same loop as before, but now fill the mask. maybe there are faster ways... don't know
        for(int y=currentBlock.y; y<currentBlock.y+currentBlock.height; ++y)
            for(int x=currentBlock.x; x<currentBlock.x+currentBlock.height; ++x)
            {
                if((y < img.rows)&&(x < img.cols))
                {
                    mask.at<unsigned char>(y,x) = blockColor;   // set mask block color
                }
            }
    }

// copy the image masked
cv::Mat combined;
img.copyTo(combined,mask);


// writing results to show you
cv::imwrite("fingerprintInput.png", thres);

cv::imshow("mask",mask);
cv::imwrite("fingerprintMask.png", mask);

cv::imshow("combined", combined);
cv::imwrite("fingerprintCombined.png", combined);


cv::waitKey(-1);
return 0;
}

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

введите здесь описание изображения

вывод:

маска для > 30% белого пикселя в блоке:

введите здесь описание изображения

комбинированная маска и ввод (здесь ввод = пороговое значение):

введите здесь описание изображения

person Micka    schedule 19.03.2014
comment
МОЙ БОГ. Я только что вернулся. Большое вам спасибо за вашу помощь! Я попробую 2moro, когда проснусь. Вы спасатель!!!! - person user3396218; 19.03.2014

Вы ищете Mat::copyTo() и используйте второе изображение как mask.

C++: void Mat::copyTo(OutputArray m, InputArray mask) const

Parameters: 
    m – Destination matrix. If it does not have a proper size or type before the operation, it is reallocated.
    mask – Operation mask. Its non-zero elements indicate which matrix elements need to be copied.
person herohuyongtao    schedule 19.03.2014
comment
спасибо, это даст мне результат изображения 2 (рис. 8.9). Но как насчет первого изображения? Есть ли какой-нибудь способ получить результат, показанный на рис. 8.8? Или мне нужно отображать каждое значение пикселя с помощью функции cvGetReal2d? - person user3396218; 19.03.2014
comment
@user3396218 user3396218 Разве рисунок 8.8 не является вашим входным изображением? - person herohuyongtao; 19.03.2014
comment
Привет. Возможно, мой вопрос был недостаточно ясен. Я уже обновил свой вопрос. - person user3396218; 19.03.2014

Для этого вам нужно использовать пороговое значение. См. http://docs.opencv.org/doc/tutorials/imgproc/threshold/threshold.html

Судя по всему, вам понадобится двоичный или двоичный (перевернутый).

person Nallath    schedule 19.03.2014