Обнаружьте монету и оттуда измерьте лист на изображении

Друзья, я пытаюсь сначала обнаружить монету, так как я уже знаю, что ее размер составляет 1,011 см2. А затем измерьте листья на изображении. Я использую findContours, но я не всегда могу сначала отличить валюту, я также пытался использовать hougCircles, но в моем случае это не работает. У кого-нибудь есть идеи?

OpenCv 4.5.0 С++

Мой код

//variables for segmentation image
cv::Mat imagem_original, imagem_gray, imagem_binaria, imagem_inRange, imagem_threshold, dst, src;
vector<Vec3f> circles;
cv::Scalar min_color = Scalar(50, 50, 50);
cv::Scalar max_color = Scalar(90, 120, 180);
imagem_original = load_image("IMG_1845.jpg");
//imshow("Imagem Original", imagem_original);

cv::cvtColor(imagem_original, imagem_gray, COLOR_BGR2GRAY);
//imshow("imagem_gray", imagem_gray);

//cv::inRange(imagem_gray, min_color, max_color, imagem_inRange);
cv::threshold(imagem_gray, imagem_threshold, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
imshow(" Threshold", imagem_threshold);


// find outer-contours in the image these should be the circles!
cv::Mat conts = imagem_threshold.clone();
std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> hierarchy;

cv::findContours(conts, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, cv::Point(0, 0));


int total_IAF = 0;
cout << "\n\n";
cout << contours.size() << "\n\n";
for (int i = 0; i < contours.size(); i++) {

    int area = contourArea(contours[i]);
    if (area <= 10) {
        cv::drawContours(imagem_original, contours, i, Scalar(0, 0, 255));
    }
    else {
        cout << area << "\n";
        cv::drawContours(imagem_original, contours, i, Scalar(255, 0, 0));
    }
    if (area > 5000) {
        total_IAF += contourArea(contours[i]);
    }
}
imshow(" ORIGINAL ", imagem_original);

double iAF_cm2 = total_IAF / 4658;

cout << "\n\n TOTAL AREA IAF: " << total_IAF;
cout << "\n IAF em cm2: " << iAF_cm2 << " cm2\n\n";
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
187
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ваш код находит все контуры на изображении и показывает их. Поэтому я запутался в значении «сначала обнаружить монету».

Если вы хотите сначала нарисовать контур монеты, отсортируйте вектор контуров по размеру. Монета — это самый маленький объект, поэтому она будет первым элементом вектора после сортировки (конечно, перед сортировкой следует удалить некоторые ненужные контуры).

Я думаю, что этот ответ лучше подходит в качестве комментария, мой друг.

stateMachine 10.12.2020 04:28

у него/нее недостаточно репутации, чтобы комментировать.

Ema 10.12.2020 06:50
Ответ принят как подходящий

Если ваша установка имеет постоянный беловатый/сероватый фон и зеленые листья, я бы использовал цветовое пространство HSV для обнаружения всех объектов с помощью канала S (зеленые листья и золотая часть монеты будут значительно больше насыщенности, чем фон), а затем различите монету и листья, используя канал H (зеленые листья будут иметь значения оттенка около 45). Осталось определить области изображения всех контуров и установить область изображения монеты в качестве своего рода эталонной области для расчета площадей объекта относительно. площадь объекта монеты 1.011.

Это канал насыщения данного изображения:

Пороговое значение канала насыщения равно 64:

Это канал оттенка изображения:

Вот некоторый код, реализующий приведенную выше идею:

int main()
{
    // Read image
    cv::Mat img = cv::imread("Wcj1R.jpg", cv::IMREAD_COLOR);

    // Convert image to HSV color space, and split H, S, V channels
    cv::Mat img_hsv;
    cv::cvtColor(img, img_hsv, cv::COLOR_BGR2HSV);
    std::vector<cv::Mat> hsv;
    cv::split(img_hsv, hsv);

    // Binary threshold S channel at fixed threshold
    cv::Mat img_thr;
    cv::threshold(hsv[1], img_thr, 64, 255, cv::THRESH_BINARY);

    // Find most outer contours only
    std::vector<std::vector<cv::Point>> cnts;
    std::vector<cv::Vec4i> hier;
    cv::findContours(img_thr.clone(), cnts, hier, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);

    // Iterate found contours
    std::vector<cv::Point> cnt_centers;
    std::vector<double> cnt_areas;
    double ref_area = -1;
    for (int i = 0; i < cnts.size(); i++)
    {
        // Current contour
        std::vector<cv::Point> cnt = cnts[i];

        // If contour is too small, discard
        if (cnt.size() < 100)
            continue;

        // Calculate and store center (just for visualization) and area of contour
        cv::Moments m = cv::moments(cnt);
        cnt_centers.push_back(cv::Point(m.m10 / m.m00 - 30, m.m01 / m.m00));
        cnt_areas.push_back(cv::contourArea(cnt));

        // Check H channel, whether the contour's image parts are mostly green
        cv::Mat mask = hsv[0].clone().setTo(cv::Scalar(0));
        cv::drawContours(mask, cnts, i, cv::Scalar(255), cv::FILLED);
        double h_mean = cv::mean(hsv[0], mask)[0];

        // If it's not mostly green, that's the coin, thus the reference area
        if (h_mean < 40 || h_mean > 50)
            ref_area = cv::contourArea(cnt);
    }

    // Iterate all contours again
    for (int i = 0; i < cnt_centers.size(); i++)
    {
        // Calculate actual object area
        double area = cnt_areas[i] / ref_area * 1.011;

        // Put area on image w.r.t. the contour's center
        cv::putText(img, std::to_string(area), cnt_centers[i], cv::FONT_HERSHEY_COMPLEX_SMALL, 1, cv::Scalar(255, 255, 255));
    }

    return 0;
}

И это будет вывод:

Спасибо за ответ, я как-то не подумал об этом!

zedaoreia 10.12.2020 13:02

Другие вопросы по теме