image.rows и image.cols меньше реального размера изображения (c ++) - PullRequest
0 голосов
/ 24 сентября 2019

Я изучаю open cv, я написал код, который должен добавить к изображению солевой и бумажный шум (он превращает значение некоторого случайного пикселя в 255), мой размер изображения 256 * 256.Проблема в том, что я не могу получить доступ ко всем пикселям, а код просто меняет половину пикселей изображения.Например, мой размер изображения, как я уже сказал, составляет 256 * 256, и когда я изменяю значение пикселя, которое находится в 256 * 256, оно меняет пиксель центрального изображения.

inline cv::Mat salt(cv::Mat, int); //my function

int main()
{

     int present, imagepixel;
     cv::Mat image = cv::imread("sample.jpg");
     imagepixel = image.rows * image.cols;
     std::cout << "enter the value of salt and paper :";
     std::cin >> percent; 
     present = (present * imagepixel) / 100; //image pixel is number of image's pixels

     if (image.empty())
     {
          std::cout << "image is not valid" << std::endl;
     }

     image = salt(image, present);
     cv::imshow("salt&paper", image);
     cv::waitKey(0);
     return 0;
}

cv::Mat salt(cv::Mat image, int present)
{
     int row, col, j = 0;
     srand(time(NULL));

     for (int i = 0; i < present; i++)
     {
          row = rand() % image.rows;
          col = rand() % image.cols;
          image.at<unsigned char>(row, col) = 255;
     }
     return image;
}

так: 1. почему изображение имеет большестрок и столбцов, чем рассчитывается с помощью функций, таких как image.rows и image.cols (я даю значение для image, в режиме отладки и image, имеет значение вне диапазона image.rows и image.cols)?2. почему выход должен быть установлен на неопределенный символ?Почему значение пикселей не может быть целым числом? (Я предполагал, что внутри image.at, это вид вывода (int, char, float)) 3. Почему этот код не может получить доступ ко всем пикселям?(скриншот добавил взгляд на результат)

Description

1 Ответ

2 голосов
/ 24 сентября 2019

Второй аргумент imread определяет способ чтения изображения.Значение по умолчанию IMREAD_COLOR, что означает, что:

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

, поэтому ваш результат mat имеет разрешение 256x256 и каждый пиксель описывается 3 значениями: для хранения Blue , Зеленый и Красный компонент пространства цвета.Эти компоненты хранятся по типу uchar (диапазон [0,255)).

2D-изображения в OpenCV хранятся построчно.Приведенную ниже формулу можно использовать для вычисления адреса элемента M(row,col):

addr(M[row,col]) = data + step1 * row + step2 * col 

, где data - первый байт массива, в котором хранятся данные изображения.Ваш мат имеет 3 канала, а ширина изображения 256, поэтому step1 равно 256 * 3 (это число столбцов в строке, умноженное на количество каналов на пиксель), а step2 равно 3.

Теперь давайте откроем исходный код at функции-члена:

template<typename _Tp> inline
_Tp& Mat::at(int i0, int i1) {
    return ((_Tp*)(data + step.p[0] * i0))[i1];
}
// i0 means row, i1 means col

в вашем коде вы указываете _Tp как uchar.Теперь просто правила работы с арифметикой указателей, которые позволяют получить доступ только к 1/3 входного изображения.Например, когда вы звоните <uchar>(0,1), вы получаете доступ к Зеленому компоненту (0,0) пикселей.

Чтобы решить вашу проблему, вы должны передать Vec3b в списке аргументов шаблона:

image.at<cv::Vec3b>(row, col) = cv::Vec3b(255,255,255);

(каждый компонент Vec3b имеет тип uchar).

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