#c #opencv
Вопрос:
Я некоторое время работаю с OpenCV и экспериментирую с расширением DNN. Моя модель имеет форму ввода [1, 3, 224, 244] с глубиной пикселя uint8. Поэтому я помещаю в функцию свой m_inputImg, который имеет 3 канала и 8-битную глубину пикселей:
cv::dnn::blobFromImage(m_inputImg, m_inputImgTensor, 1.0, cv::Size(), cv::Scalar(), false, false, CV_8U);
Теперь мне интересно получить представление о том, как мое входное изображение «лежит» внутри тензора cv::Mat. Теоретически я знаю, как выглядит тензор, но я не понимаю, как OpenCV это делает. Поэтому, чтобы понять это, я хочу извлечь один цветовой канал. Я пробовал это:
cv::Mat blueImg = cv::Mat(cp->getModelConfigs().model[0].input.height,
cp->getModelConfigs().model[0].input.width,
CV_8UC3,
blob.ptr<uint8_t>(0, 0);
Но то, что я получаю, — это что-то вроде этого (см. Рисунок). Я действительно в замешательстве по этому поводу, может ли кто-нибудь помочь или дать хороший совет?
Спасибо
Комментарии:
1. Как выглядит ваше исходное изображение? Если вы хотите отобразить только 1 канал, почему вы используете CV_8UC3 имхо, в настоящее время вы отображаете весь тензор как BGRBGRBGR… но ваши данные должны быть упорядочены RRR…GGG…BBB… можете ли вы попробовать просто использовать CV_8UC1? Имхо, тогда вы должны получить RRR… изображение. Но я не уверен, почему в вашем большом двоичном объекте 9 изображений.
2. При создании большого двоичного объекта не должно быть cv::Size(224,224) вместо cv::Size()?
3. Когда я попробую CV_8UC1, я получу только шум на своем изображении, поэтому мой указатель может отображаться в неопределенных областях.
4. Для параметра size OpenCV напишите следующее: «размер: пространственный размер выходного изображения». Поэтому, на мой взгляд, cv::Size(224, 224) неверен, потому что выходное «изображение» — это тензор. Но я понятия не имею, какой размер следует использовать, поэтому я разрешил это по умолчанию (возможно, OpenCV знает, чего я хочу… :D)
5. На вашем изображении первая 1/3 изображения является первым каналом большого двоичного объекта. Поскольку вы интерпретируете канал моноблока как изображение с 3 каналами, он будет считывать вторую строку изображения после 1/3 отображаемого изображения и третью строку на 2/3 отображаемого изображения. Поскольку вы читаете больше строк, чем требуется, второй канал начинается с 1/3 строк отображаемых изображений, а третий канал начинается с 2/3.
Ответ №1:
cv::Size() будет использовать исходный размер изображения. Вы неправильно интерпретируете данные. Вот 4 способа интерпретации cv::Size()
загруженного большого двоичного объекта 512×512 ()-начните с изображения Ленны:
вход (512×512):
- большой двоичный объект-запускается как одноканальное изображение 512×512:
- большой двоичный объект-начните с изображения размером 512×512 BGR:
- большой двоичный объект-начните с изображения размером 224×224 BGR:
- большой двоичный объект-запуск в виде одного канала 224×224:
вот код:
int main()
{
cv::Mat img = cv::imread("C:/data/Lenna.png"); // 8UC3
cv::imshow("img", img);
cv::Mat blob;
cv::dnn::blobFromImage(img, blob, 1.0, cv::Size(), cv::Scalar(), false, false, CV_8U);
cv::Mat redImg = cv::Mat(img.rows,
img.cols,
CV_8UC1,
blob.ptr<uint8_t>(0, 0));
cv::imshow("blob 1", redImg);
cv::imwrite("red1.jpg", redImg);
cv::Mat redImg3C = cv::Mat(img.rows,
img.cols,
CV_8UC3,
blob.ptr<uint8_t>(0, 0));
cv::imshow("redImg3C", redImg3C);
cv::imwrite("red3C.jpg", redImg3C);
cv::Mat redImg224_3C = cv::Mat(224,
224,
CV_8UC3,
blob.ptr<uint8_t>(0, 0));
cv::imshow("redImg224_3C", redImg224_3C);
cv::imwrite("redImg224_3C.jpg", redImg224_3C);
cv::Mat redImg224_1C = cv::Mat(224,
224,
CV_8UC1,
blob.ptr<uint8_t>(0, 0));
cv::imshow("redImg224_1C", redImg224_1C);
cv::imwrite("redImg224_1C.jpg", redImg224_1C);
cv::waitKey(0);
}
Имхо, вы должны сделать в своем коде:
cv::dnn::blobFromImage(m_inputImg, blob, 1.0, cv::Size(), cv::Scalar(), false, false, CV_8U);
cv::Mat blueImg = cv::Mat(m_inputImg.rows,
m_inputImg.cols,
CV_8UC3,
blob.ptr<uint8_t>(0, 0);
или
cv::dnn::blobFromImage(m_inputImg, blob, 1.0, cv::Size(cp->getModelConfigs().model[0].input.width , cp->getModelConfigs().model[0].input.height), cv::Scalar(), false, false, CV_8U);
cv::Mat blueImg = cv::Mat(cp->getModelConfigs().model[0].input.height,
cp->getModelConfigs().model[0].input.width,
CV_8UC3,
blob.ptr<uint8_t>(0, 0);
Кроме того, вот версия установки размера изображения пространственного большого двоичного объекта на фиксированный размер (например, желаемый размер ввода DNN).:
cv::Mat blob2;
cv::dnn::blobFromImage(img, blob2, 1.0, cv::Size(224,224), cv::Scalar(), false, false, CV_8U);
cv::Mat blueImg224_1C = cv::Mat(224,
224,
CV_8UC1,
blob2.ptr<uint8_t>(0, 0));
cv::imshow("blueImg224_1C", blueImg224_1C);
cv::imwrite("blueImg224_1C.jpg", blueImg224_1C);
Комментарии:
1. в образце допущена ошибка. Это не красный канал, так как я не менял каналы во время BLOB-изображения. Вместо этого это СИНИЙ канал, но все равно основное сообщение остается тем же самым.
2. Мне кажется, я понимаю это немного лучше. Но в своем редактировании вы предоставляете образец для извлечения «СИНЕГО» канала, но в результирующем изображении он легко выглядит как изображение в оттенках серого от исходного изображения.
3. рисование одного канала всегда серого цвета. Если вы хотите отобразить его в виде цветного изображения, вам придется объединить один канал с 2 пустыми каналами. Например:
std::vector<cv::Mat> bgrMerger; bgrMerger.push_back(blueMat); bgrMerger.push_back(emptyMat); bgrMerger.push_back(emptyMat);
тогдаcv::merge(bgrMerger, bgrImage);
иcv::imshow("image", bgrImage);
4. Да, вы правы. Но, на мой взгляд, будут отображаться только пиксели со значением >0 в синем канале. Кажется, все по-другому, когда я смотрю на ваш образец изображения.