Есть матрица OpenCV:
cv::Mat m;
Нужно, например, пробежаться по ней циклом и вывести значения всех каналов каждого пикселя. В одном проекте (OpenVINO samples, но это не так важно) для этого используется такой цикл:
for (size_t c = 0; c < channels; c++) {
for (size_t h = 0; h < height; h++) {
for (size_t w = 0; w < width; w++) {
std::cout << m.at<cv::Vec3b>(h, w)[c];
}
}
}
Попытка использовать этот кусочек в моём приложении привела к тому, что все изображения оказались битыми. Пришлось разбираться с циклом. И я теперь не могу понять, не содержит ли он ошибку.
Допустим изображение 1-канальное (один из случаев, в котором я безуспешно пытался применить этот цикл). Тогда, казалось бы, все значения пикселей должны лежать последовательно как переменные unsigned char
, это значит, что разница между адресами соседних пикселей должна быть равна 1, вывожу на экран:
std::cout << (void*)&(m.at<cv::Vec3b>(10, 7)[0]) << std::endl;
std::cout << (void*)&(m.at<cv::Vec3b>(10, 8)[0]) << std::endl;
и вижу совсем не то:
0000017C9F7123D5
0000017C9F7123D8
С другой стороны всё правильно, если мы интерпретируем позицию как 3-вектор, то разница адресов должна быть как раз 3 байта (uchar). Но тогда цикл выше некорректно работает для изображений, у которых не 3 канала. Выходит, что у Intel в их примерах ошибка.
Как же на самом деле следует обращаться к пикселям cv::Mat
? Содержит ли цикл выше ошибку, или это я неправильно его применил?
Для одноканальных изображений (CV_8UC1
) вместо m.at<cv::Vec3b>
должно быть m.at<uchar>()
, для другой канальности соответственно нужно поменять тип.
Да, каждая строка матрицы лежит последовательно (между строками может быть зазор, обусловленный выравниванием step), это можно использовать при работе на низком уровне - через ptr()
как указатель на начало всего блока данных или конкретную строку адресовать байтовый массив
#include <cstdio>
#include <opencv2/imgcodecs.hpp>
int main(){
cv::Mat m = cv::imread("img.bmp");
unsigned size = m.cols * m.rows * m.channels();
for(unsigned i = 0; i < size; ++i) printf((i+1) % m.channels() ? "%02X " : "%02X\n", m.data[i]);
return 0;
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Помогите разобраться, пожалуйстаИмеем несколько элементов с одинаковым классом
Дано такое задание: Разработать консольное приложение "Поиск последнего созданного файла с заданным расширением":
Я методом Find заменяю некоторые слова, потом сохраняю ворд как пдф, но мне так надо сделать 100 разИ что бы не сохранять изменения а получить...