Цветовая фильтрация с зависимостями между цветами

Моя текущая цель — создать цветовой фильтр (возможно, пороговый), который создает маску для областей с чем-то вроде следующих отношений:

B < G

G > 128

R > 1.5 * G

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

На предыдущей машине (NUCi7) результирующая программа могла достигать примерно 6-10 кадров в секунду, но она выполнялась полностью на процессоре. Теперь я переключился на Jetson Xavier NX, чтобы посмотреть на OpenCV, ускоренный графическим процессором. В настоящее время я ищу функцию или несколько, которые могут эффективно реализовать эти условия.

Я не пытаюсь найти наиболее эффективный способ, если он слишком сложен для начала. Но я протестировал несколько алгоритмов отслеживания объектов, которые отлично работал на 40+ FPS и изображениях HD2K, поэтому я надеюсь, что есть способ сделать это и получить 40+/60+ FPS.

Что-то вроде функции inRange было бы здорово, но, похоже, это не так. еще существуют для GPU-OpenCV. Возможно, есть умный способ реализовать это с помощью thresholds, но пока я нашел его только со статическими значениями.

.

https://docs.opencv.org/2.4/modules/gpu/doc/image_processing.html

image.forEach<Pixel>
        (
            [&](Pixel &pixel, const int * position) -> void
            {
                if (pixel.z > 1.5 * pixel.y &&
                    (pixel.y > pixel.x) && 
                    pixel.y > 128){
                        pixel.z = 255;
                        pixel.y = 255;
                        pixel.x = 255;
                } else {
                        pixel.z = 0;
                        pixel.y = 0;
                        pixel.x = 0;
                }
            }
        );

Код в основном это , с которого я хочу начать. Применение цикла foreach сверху.

Фактический текущий код таков:

while (viewer.isAvailable()) {
        // Grab images
        if (zed.grab(runtime_parameters) == ERROR_CODE::SUCCESS) {

            // Retrieve left image
            zed.retrieveImage(image_zed, VIEW::LEFT, MEM::GPU,new_image_size);
            cv::Mat image_ocv = slMat2cvMat(image_zed);

            // <!-- Everything here is a test to insert a custom 3D-Bounding box into the live-image
            sl::ObjectData newObject;
            sl::ObjectData refObject;
            std::cout << "\n\nNew Loop" << endl;

            // Retrieve Detected Human Bodies
            zed.retrieveObjects(objects, objectTracker_parameters_rt);

            int id = 42;
            sl::float3 newPosition = {-.1,.1,-0.5};
            sl::float3 newVelocity = {.0,.0,.0};
            
            std::vector<sl::float3> newBounding_box;
            sl::float3 pOri = {looper[0],looper[1],looper[2]};
            sl::float3 pDim = {0.25,0.25,0.25};
            sl::float3 p0 = {pOri[0]-pDim[0]/2,pOri[1]-pDim[1]/2,pOri[2]-pDim[2]/2};
            sl::float3 p1 = {pOri[0]-pDim[0]/2,pOri[1]-pDim[1]/2,pOri[2]+pDim[2]/2};
            sl::float3 p2 = {pOri[0]+pDim[0]/2,pOri[1]-pDim[1]/2,pOri[2]+pDim[2]/2};
            sl::float3 p3 = {pOri[0]+pDim[0]/2,pOri[1]-pDim[1]/2,pOri[2]-pDim[2]/2};
            sl::float3 p4 = {pOri[0]-pDim[0]/2,pOri[1]+pDim[1]/2,pOri[2]-pDim[2]/2};
            sl::float3 p5 = {pOri[0]-pDim[0]/2,pOri[1]+pDim[1]/2,pOri[2]+pDim[2]/2};
            sl::float3 p6 = {pOri[0]+pDim[0]/2,pOri[1]+pDim[1]/2,pOri[2]+pDim[2]/2};
            sl::float3 p7 = {pOri[0]+pDim[0]/2,pOri[1]+pDim[1]/2,pOri[2]-pDim[2]/2};
            std::vector<sl::uint2> newBounding_box_2d = {
                {250,30},
                {1500,30},
                {1500,500},
                {250,500}};
            newBounding_box.push_back(p0);
            newBounding_box.push_back(p1);
            newBounding_box.push_back(p2);
            newBounding_box.push_back(p3);
            newBounding_box.push_back(p4);
            newBounding_box.push_back(p5);
            newBounding_box.push_back(p6);
            newBounding_box.push_back(p7);
            sl::float3 newDimensions = {1.0,1.0,1.0};

            newObject.id = id;
            newObject.position = pOri;
            newObject.velocity = newVelocity;
            newObject.bounding_box_2d = newBounding_box_2d;
            newObject.bounding_box = newBounding_box;
            newObject.dimensions = pDim;
            objects.object_list.push_back(newObject);
            // --> End of the 3D-Bounding box insert

/*          image_ocv.forEach<Pixel>
                (
                    [&](Pixel &pixel, const int * position) -> void {
                        if (pixel.z > 1.5 * pixel.y && pixel.y > pixel.x && pixel.y > 128) {
                            pixel.z = 255; pixel.y = 255; pixel.x = 255;
                        } else {
                            pixel.z = 0; pixel.y = 0; pixel.x = 0;
                        }
                    }
                );*/
            //Update GL View
            viewer.updateView(image_zed, objects);
        }
    }
cv::Mat slMat2cvMat(Mat& input) {
    // Mapping between MAT_TYPE and CV_TYPE
    int cv_type = -1;
    switch (input.getDataType()) {
        case MAT_TYPE::F32_C1: cv_type = CV_32FC1; break;
        case MAT_TYPE::F32_C2: cv_type = CV_32FC2; break;
        case MAT_TYPE::F32_C3: cv_type = CV_32FC3; break;
        case MAT_TYPE::F32_C4: cv_type = CV_32FC4; break;
        case MAT_TYPE::U8_C1: cv_type = CV_8UC1; break;
        case MAT_TYPE::U8_C2: cv_type = CV_8UC2; break;
        case MAT_TYPE::U8_C3: cv_type = CV_8UC3; break;
        case MAT_TYPE::U8_C4: cv_type = CV_8UC4; break;
        default: break;
    }

    // Since cv::Mat data requires a uchar* pointer, we get the uchar1 pointer from sl::Mat (getPtr<T>())
    // cv::Mat and sl::Mat will share a single memory structure
    return cv::Mat(input.getHeight(), input.getWidth(), cv_type, input.getPtr<sl::uchar1>(MEM::GPU));
}

Код как есть работает, но добавленный ForEach-Loop приводит к ошибке сегментации.

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


person kremerf    schedule 13.11.2020    source источник
comment
Это выглядит как довольно простой тест на пиксель; только тот, который может быть не написан заранее. Вы изучали языки шейдеров (cuda, glsl, sksl и т. д.)? Какой уровень переносимости вам нужен? (Только Nvidia?) Какой вывод вам нужен и куда он должен идти? Образ уже на GPU? Вы пробовали многопоточность на основе строки сканирования? О каком количестве пикселей идет речь?   -  person Yakk - Adam Nevraumont    schedule 13.11.2020
comment
Вы работаете в выпуске? сколько это занимает? пожалуйста, покажите минимально воспроизводимый пример, который другие могут скопировать и вставить   -  person Miki    schedule 13.11.2020
comment
Это нужно только для работы на xavier, не собираюсь использовать его где-то еще. Цель состоит в том, чтобы сократить каждое живое видеоизображение до областей, удовлетворяющих этим условиям, поэтому некоторая форма cv::Mat или sl::Mat была бы отличной. Изображение находится на графическом процессоре, как по умолчанию в программе StereoLabs. Не рассматривал многопоточность на основе строки сканирования, сделаю это. 3840х1080 и 2560х720.   -  person kremerf    schedule 13.11.2020
comment
Я включил ссылку на код внизу вопроса.   -  person kremerf    schedule 13.11.2020
comment
Вы пытались выполнить операцию Mat напрямую вместо сравнения на уровне пикселей. Возможно, что операции Mat ускоряются, а затем объединяются вместе, что дает лучшие результаты, чем на уровне пикселей один. Например, создание мата маски для G > 128, ...   -  person Jean-Marc Volle    schedule 13.11.2020
comment
Моя самая большая проблема с использованием различных решений заключается в том, что каждый подход OpenCV приводит к ошибке сегментации. Я должен сначала решить это, чтобы оценить дальше.   -  person kremerf    schedule 16.11.2020