У меня есть модуль на Python, который отправляет RGB на C ++ и там его потребляют. Однако изображение имеет неправильное цветовое пространство, независимо от того, что я делаю. То есть я попытался преобразовать его в RGB
, предполагая, что он все еще находится в BGR (хотя в python он намеренно преобразован в RGB, выполнив: return img[:,:,::-1]
и визуализируйте изображение с помощью matplotlib.) И наоборот, они выглядят одинаково!
Это показано ниже:
Исходное изображение:
Это вывод изображения без какого-либо вмешательства
Это результат, когда я использую преобразование цветового пространства из BGR2RGB:
cv::Mat img2;
cv::cvtColor(img, img2, cv::COLOR_BGR2RGB);
cv::imshow(title + " type:" + image_type, img2);
И вот что я получаю, когда пытаюсь преобразовать как RGB2BGR:
cv::Mat img2;
cv::cvtColor(img, img2, cv::COLOR_RGB2BGR);
cv::imshow(title + " type:" + image_type, img2);
И, как видите, два последних идентичны. Поэтому я попытался вручную изменить каналы и посмотреть, смогу ли я заставить это работать. Фрагмент кода:
cv::Mat img2;
cv::cvtColor(img, img2, cv::COLOR_RGB2BGR);
//cv::cvtColor(img, img2, cv::COLOR_BGR2RGB);
for (int i = 0; i < img.rows; i++) {
for (int j = 0; j < img.cols; j++) {
img2.at<cv::Vec3b>(i, j)[2] = img.at<cv::Vec3b>(i, j)[0];
img2.at<cv::Vec3b>(i, j)[0] = img.at<cv::Vec3b>(i, j)[1];
img2.at<cv::Vec3b>(i, j)[1] = img.at<cv::Vec3b>(i, j)[2];
}
}
cv::imshow(title + " type:" + image_type, img2);
Вот результат:
Очевидно, что это RGB, и все выглядит хорошо, и кажется, что изображение было в формате GBR! Я понятия не имею, что вызывает это.
Также я заметил, что я должен выполнить преобразование, иначе следующие циклы for сообщат мне нарушения доступа к памяти! что мне странно! Изменение BGR2RGB
или RGB2BGR
в cvtColor
не имеет никакого эффекта, и они действуют одинаково.
Я также хотел бы знать, есть ли лучший способ поместить это в правильное цветовое пространство, что-то, что не требует цикла for, подобного тому, который я написал, и использует аппаратное ускорение? Поскольку эта операция должна быть быстрой, но использование текущего решения, которое у меня есть, совсем не годится.
Редактировать
Кстати, это функция Python, которую я вызывал в своем C ++:
def detect_and_align_all(pil_img):
"""gets the input image, and returns all the faces aligned as a list of rgb images
"""
bboxes, landmarks = detect_faces(pil_img)
# convert to ndarray and then make rgb to bgr
cv_img = np.array(pil_img)[:, :, ::-1].copy()
img_list = []
for landmark in landmarks:
img = align_face(cv_img, landmark)
img_list.append(img[:, :, ::-1])
return img_list
и align_face
в конечном итоге называет это:
return cv2.warpAffine(cv_img, tfm, (crop_size[0], crop_size[1]))
Обновление 1
Это фрагменты (взятые отсюда), которые я использую для отправки изображения из c ++ в python с помощью Pybind11:
py::dtype determine_np_dtype(int depth)
{
switch (depth)
{
case CV_8U: return py::dtype::of<uint8_t>();
case CV_8S: return py::dtype::of<int8_t>();
case CV_16U: return py::dtype::of<uint16_t>();
case CV_16S: return py::dtype::of<int16_t>();
case CV_32S: return py::dtype::of<int32_t>();
case CV_32F: return py::dtype::of<float>();
case CV_64F: return py::dtype::of<double>();
default:
throw std::invalid_argument("Unsupported data type.");
}
}
std::vector<std::size_t> determine_shape(cv::Mat& m)
{
if (m.channels() == 1) {
return {
static_cast<size_t>(m.rows)
, static_cast<size_t>(m.cols)
};
}
return {
static_cast<size_t>(m.rows)
, static_cast<size_t>(m.cols)
, static_cast<size_t>(m.channels())
};
}
py::capsule make_capsule(cv::Mat& m)
{
return py::capsule(new cv::Mat(m)
, [](void* v) { delete reinterpret_cast<cv::Mat*>(v); }
);
}
py::array mat_to_nparray(cv::Mat& m)
{
if (!m.isContinuous()) {
throw std::invalid_argument("Only continuous Mats supported.");
}
return py::array(determine_np_dtype(m.depth())
, determine_shape(m)
, m.data
, make_capsule(m));
}
и используется так:
py::scoped_interpreter guard{};
auto module = py::module::import("MyPackage.align_faces");
auto aligner = module.attr("align_all");
auto pil_converter = module.attr("cv_to_pil");
auto img = cv::imread("image1.jpg");
auto img_pil = pilConvertor(mat_to_nparray(img));
auto img_face_list = aligner(img_pil);
Обновление 2
Благодаря @DanMasek в комментариях, сохраняя копию изображений на стороне Python, непосредственно перед отправкой их обратно на C ++, вышеуказанная проблема решена. Однако, как указал Ext3h в комментариях, в изображении также есть артефакт, который не исчез даже после последнего изменения.
Я сохранил два изображения (режим bgr) как на Python, так и на C ++, используя imwrite
, артефакт, который здесь показан, не отображается на этих изображениях. однако между двумя изображениями есть небольшая разница. изображение cpp немного увеличено по сравнению с версией python (они оба используют одну и ту же функцию (на самом деле c ++ вызывает для этого один и тот же модуль python)). и версия Python также больше по размеру:
cpp изображение (размер: 5492 байта):
Изображение Python (размер: (5 587 байт)
В чем проблема? коды, которые я использовал, на самом деле не изменяют шаги / смещения любого вида), тогда что препятствует этой проблеме?
[2]
в своей третьей строке, вы обнаруживаете, что она равна[0]
из-за первой строки. вы должны использовать временную переменную для хранения старого значения[2]
. - person bracco23   schedule 05.08.2020img
и записывает вimg2
, поэтому его не перезаписывают. - person Rika   schedule 05.08.2020RGB
и случайной интерпретацией его какGBR
есть только одно смещение байта, позднее также включает проблемы с выравниванием в OpenCV. На самом деле отстает более чем на один, так как у вас также есть этот рыбный артефакт, показывающий справа от лица. Это означает, что вы полностью не выровнены. - person Ext3h   schedule 05.08.2020img_list.append(img[:, :, ::-1])
, чтобы добавить его копию? Я помню, что основные привязки OpenCV не любят представления массивов с такими перевернутыми индексами, возможно, это проблема для pybind (или код, который я написал в своем ответе, не учитывал такой случай)? - person Dan Mašek   schedule 05.08.2020cv::cvtColor(img, img2, cv::COLOR_BGR2RGB);
просто печатает правильное изображение! - person Rika   schedule 05.08.2020cv::Mat
. Например,[:, :, ::-1]
просто сообщает numpy о необходимости доступа к последнему измерению в обратном порядке, ноMat
OpenCV не может этого сделать. Когда у меня будет время для этого, я рассмотрю ответ, на который вы вдохновились, чтобы добавить несколько проверок для обнаружения таких несовместимостей и более глубоко исследовать эту проблему. В любом случае, создавая копию, вы сбрасываете всю эту странность индексации - это означает, что данные следует читать в странном порядке, но записывать в обычном порядке. - person Dan Mašek   schedule 06.08.2020warpAffine
... Может быть, в одном сценарии вы на самом деле не сохраняете результат преобразования? Может превратить это в новый вопрос. - person Dan Mašek   schedule 06.08.2020