Как построить изображение из вектора матриц с использованием opencv

#c #qt #opencv

#c #qt #opencv

Вопрос:

Я нахожусь в процессе разделения изображения на области прямоугольников, я нашел некоторый полезный код, который позволяет мне это делать, однако у меня возникают проблемы с пониманием того, как манипулировать каждой отдельной областью и восстанавливать их вместе, чтобы сформировать новое полное изображение того же исходного размера. Я новичок как в c , так и в opencv, поэтому буду признателен за любую помощь.

В настоящее время все прямоугольники хранятся в std::vector<cv::Mat> *blocks .

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

Это код, который разбивает изображение на прямоугольники:

     if(img.cols % colDivisor == 0 amp;amp; img.rows % colDivisor == 0){
        for(int y = 0; y < img.cols; y  = img.cols/colDivisor){
            for(int x = 0; x < img.rows; x  = img.rows/rowDivisor){
                blocks->push_back(img(cv::Rect(y, x, (img.cols / colDivisor), (img.rows / rowDivisor))).clone());
                rectangle(maskImg, cv::Point(y,x), cv::Point(y   (maskImg.cols / colDivisor) - 1, x   (maskImg.rows / rowDivisor) - 1), CV_RGB(255, 0, 0), 1);
                cv::imshow("Image", maskImg);
  

Я могу манипулировать значениями BGR выбранного изображения следующим образом:

     std::vector<cv::Mat> m;
    ...
    cv::Mat image2 =m[9]; //Random rect
    std::vector<cv::Mat> channels;
    cv::split(image2, channels);
    cv::Scalar avg1 = cv::mean(channels[0]);
    cv::Scalar avg2 = cv::mean(channels[1]);
    cv::Scalar avg3 = cv::mean(channels[2]);
    std::cout << "Blue channel: " << avg1[0] << std::endl << "Green channel: " << avg2[0] << std::endl << "Red channel: " <<  avg3[0] << std::endl;
    image2.setTo(cv::Scalar(avg1[0], avg2[0], avg3[0]));
    cv::imshow("BGRTEST", image2);
  

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

Как я мог это сделать?

Я попытался использовать итератор c , например:

 for(std::vector<cv::Mat>::iterator it = blocks->begin(); it != blocks->end();   it){

}
  

Однако я не уверен, как бы я это реализовал.

Заранее спасибо!

Ответ №1:

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

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

Вы используете область интереса, но вы копируете ее, а затем планируете объединить полученные небольшие изображения. Это не только расточительно с точки зрения вычислений, но и усложняет код.

Вот как вы можете использовать интересующую область в своих интересах:

 for(int y = 0; y < img.cols - 30; y  = 30) {
    for(int x = 0; x < img.rows - 30; x  = 30) {
        cv::Mat roi = img(cv::Rect(y, x, 30, 30));
        std::vector<cv::Mat> channels;
        cv::split(roi, channels);
        cv::Scalar avg1 = cv::mean(channels[0]);
        cv::Scalar avg2 = cv::mean(channels[1]);
        cv::Scalar avg3 = cv::mean(channels[2]);
        roi.setTo(cv::Scalar(avg1[0], avg2[0], avg3[0]));
    }
}
  

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

Комментарии:

1. Это именно то, что я искал! Жаль, что я не заметил ROI в документации Mat.. Я уже знал, что это дорого с точки зрения вычислений, поэтому я действительно надеялся, что будет какой-то другой подход. Большое спасибо!