Вероятностное преобразование линии Хафа OpenCV дает разные результаты с C ++ и Python?

Я работал над проектом с использованием OpenCV, Python, который использует функцию вероятностного преобразования линии Хафа HoughLinesP в какой-то части проекта. Мой код работал нормально, и проблем не было. Затем я подумал о преобразовании того же кода на C ++.

После преобразования кода в C ++ результат не такой, как у кода Python. После долгих часов отладки я обнаружил, что все остальное работает нормально, но функция HoughLinesP дает другой результат в случае C ++. Входные данные для этой функции на обоих языках одинаковы, и значения параметров также одинаковы, но выходные данные отличаются.

Может ли кто-нибудь объяснить мне, почему это происходит, и какие возможные способы исправления?

Кроме того, я проверил версию OpenCV для обоих языков, и она одинакова: 4.5.0 dev Кроме того, я попытался поиграть со значениями, переданными в код C ++, но не смог получить аналогичные результаты.

Входное изображение края:

Входное изображение края

Вывод Python HoughLinesP ():

Вывод Python HoughLinesP ()

Вывод C ++ HoughLinesP ():

Вывод C ++ HoughLinesP ()

Ниже приведены коды для каждого языка: Python:

Lines = cv2.HoughLinesP(EdgeImage, 1, np.pi / 180, 50, 10, 15)

C++:

std::vector<cv::Vec4i> Lines;
cv::HoughLinesP(EdgeImage, Lines, 1, CV_PI / 180, 50, 10, 15);

Было бы здорово, если бы кто-нибудь мог что-то подсказать.


person Rahul Kedia    schedule 20.10.2020    source источник


Ответы (1)


Объяснение и исправление

Проблема возникает из-за того, что в версии Python вы не устанавливаете аргументы, которые, как вы думаете, устанавливаете. В отличие от некоторых других функций, для которых списки аргументов адаптированы в интерфейсе Python, HoughLinesP не только возвращает строки, но также принимает параметр lines для вывода строки. Вы можете увидеть это в справке для HoughLinesP:

import cv2
help(cv2.HoughLinesP)

что дает вам (многоточие):

Help on built-in function HoughLinesP:

HoughLinesP(...)
    HoughLinesP(image, rho, theta, threshold[, lines[, minLineLength[, maxLineGap]]]) -> lines
    .   @brief Finds line segments in a binary image using the probabilistic Hough transform.
    .   
...
    .   @param lines Output vector of lines. Each line is represented by a 4-element vector
    .   \f$(x_1, y_1, x_2, y_2)\f$ , where \f$(x_1,y_1)\f$ and \f$(x_2, y_2)\f$ are the ending points of each detected
    .   line segment.
...

Таким образом, в вашем примере на Python вы передаете 10 как lines вместо minLineLength. Чтобы исправить это, вы можете передать пустой массив как lines или передать параметры как аргументы ключевого слова:

Lines = cv2.HoughLinesP(EdgeImage, rho=1, theta=np.pi/180,
                        threshold=50, minLineLength=10, maxLineGap=15)

Это должно привести к тому, что вывод вашей версии Python будет соответствовать версии C ++.

В качестве альтернативы, если вас устраивают результаты версии Python, вы должны оставить параметр lines (т.е. установить только minLineLength на 15 и использовать значение по умолчанию 0 для maxLineGap [см. документацию]):

std::vector<cv::Vec4i> Lines;
cv::HoughLinesP(EdgeImage, Lines, 1, CV_PI / 180, 50, 15);

Это должно воспроизвести вашу версию Python.

Пример

Используя пример, приведенный в документации openCV для HoughLinesP, можно убедитесь, что это решает проблему.

Версия C ++

(Взято из документации openCV, указанной выше, и адаптировано для сохранения изображения.)

#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
    Mat src, dst, color_dst;
    if( argc != 3 || !(src=imread(argv[1], 0)).data)
        return -1;
    Canny( src, dst, 50, 200, 3 );
    cvtColor( dst, color_dst, COLOR_GRAY2BGR );
    vector<Vec4i> lines;
    HoughLinesP( dst, lines, 1, CV_PI/180, 80, 30, 10 );
    for( size_t i = 0; i < lines.size(); i++ )
    {
        line( color_dst, Point(lines[i][0], lines[i][1]),
        Point( lines[i][2], lines[i][3]), Scalar(0,0,255), 3, 8 );
    }
    imwrite( argv[2], color_dst );
    return 0;
}

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

C ++ результат

Неправильная версия Python

(По сути, это просто переведенная версия C ++ без параметра lines.)

import argparse
import cv2
import numpy as np

parser = argparse.ArgumentParser()
parser.add_argument("input_file", type=str)
parser.add_argument("output_file", type=str)
args = parser.parse_args()

src = cv2.imread(args.input_file, 0)
dst = cv2.Canny(src, 50., 200., 3)
color_dst = cv2.cvtColor(dst, cv2.COLOR_GRAY2BGR)
lines = cv2.HoughLinesP(dst, 1., np.pi/180., 80, 30, 10.)
for this_line in lines:
    cv2.line(color_dst,
            (this_line[0][0], this_line[0][1]),
            (this_line[0][2], this_line[0][3]),
            [0, 0, 255], 3, 8)
cv2.imwrite(args.output_file, color_dst)

Выполнение этого дает следующий (другой) результат:

Неверный результат Python

Исправленная версия Python

(Исправлено путем передачи вместо этого аргументов ключевого слова)

import argparse
import cv2
import numpy as np

parser = argparse.ArgumentParser()
parser.add_argument("input_file", type=str)
parser.add_argument("output_file", type=str)
args = parser.parse_args()

src = cv2.imread(args.input_file, 0)
dst = cv2.Canny(src, 50., 200., 3)
color_dst = cv2.cvtColor(dst, cv2.COLOR_GRAY2BGR)
lines = cv2.HoughLinesP(dst, rho=1., theta=np.pi/180.,
                        threshold=80, minLineLength=30, maxLineGap=10.)
for this_line in lines:
    cv2.line(color_dst,
            (this_line[0][0], this_line[0][1]),
            (this_line[0][2], this_line[0][3]),
            [0, 0, 255], 3, 8)
cv2.imwrite(args.output_file, color_dst)

Это дает правильный результат (то есть тот же результат, что и версия C ++):

Фиксированный результат Python

person jotasi    schedule 25.10.2020
comment
Большое спасибо, @jotasi за ваш ответ. Вы спасли меня. :) ... Мне просто интересно, когда я удалил 10 из C ++, результаты оказались точно такими же, как у python. Тогда каково использование переменной 10 (строки параметров) в Python. Почему это вообще используется в качестве входных данных? - person Rahul Kedia; 26.10.2020
comment
@RahulKedia Я думаю (хотя и не пробовал), что вы можете передать массив numpy, который затем будет заполнен строками. В остальном без понятия. - person jotasi; 26.10.2020
comment
Хорошо, спасибо @jotasi, я только что завершил свой проект, и коды C ++ и Python теперь дают идентичные результаты. - person Rahul Kedia; 26.10.2020