为什么 CV::Mat 图像的颜色空间错误(GBR 而不是 RGB 或 BGR)?

2024-01-25

我有一个 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 or RGB2BGR in the cvtColor没有任何效果,并且它们的行为相同。

我还想知道是否有更好的方法将其放入正确的色彩空间,不需要像我编写的那样的 for 循环并使用硬件加速?由于此操作需要快速,但使用我当前的解决方案根本不好。

Edit

顺便说一句,这是我在 C++ 中调用的 Python 函数:

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

and align_face最终称之为:

return cv2.warpAffine(cv_img, tfm, (crop_size[0], crop_size[1]))

Update 1

这些是我使用 Pybind11 将图像从 c++ 发送到 python 的片段(取自此处):

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);

Update 2

感谢评论中的@DanMasek,通过在将图像发送回 C++ 之前将图像副本存储在 python 端,上述问题得到了解决。然而,正如 Ext3h 在评论中指出的那样,图像中也存在伪影,即使在最新的更改之后也没有消失。

我使用 Python 和 C++ 保存了两个图像(bgr 模式)imwrite,此处显示的工件并未出现在这些图像中。然而,这两个图像之间存在细微差别。与 python 版本相比,cpp 图像有点放大(它们都使用完全相同的函数(事实上,c++ 为此调用完全相同的 python 模块))。 Python 版本的尺寸也更大:

cpp 图像(大小:5,492 字节):

Python图像(大小:(5,587字节)

这里有什么问题?事实上,我使用的代码不会改变任何类型的步幅/偏移)那么是什么阻止了这个问题呢?


None

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 CV::Mat 图像的颜色空间错误(GBR 而不是 RGB 或 BGR)? 的相关文章

  • c# 从另一个类中的另一个静态事件引发事件

    需要帮助从另一个班级调用事件 我有已声明事件的课程 public class MxPBaseGridView GridView public event AddNewItemsToPopUpMenuEventHandler AddNewIt
  • 我如何知道 C 程序的可执行文件是在前台还是后台运行?

    在我的 C 程序中 我想知道我的可执行文件是否像这样在前台运行 a out 或者像这样 a out 如果你是前台工作 getpgrp tcgetpgrp STDOUT FILENO or STDIN FILENO or STDERR FIL
  • 锁定 ASP.NET 应用程序变量

    我在 ASP NET 应用程序中使用第三方 Web 服务 对第 3 方 Web 服务的调用必须同步 但 ASP NET 显然是多线程的 并且可能会发出多个页面请求 从而导致对第 3 方 Web 服务的同时调用 对 Web 服务的调用封装在自
  • C free() 是如何工作的? [复制]

    这个问题在这里已经有答案了 可能的重复 malloc 和 free 如何工作 https stackoverflow com questions 1119134 how malloc and free work include
  • 并行化斐波那契序列生成器

    我正在学习并行化 在一项练习中 我得到了一些我应该提高性能的算法 其中之一是斐波那契数列生成器 array 0 0 array 1 1 for q 2 q lt MAX q array q array q 1 array q 2 我怀疑 这
  • 进程退出后 POSIX 名称信号量不会释放

    我正在尝试使用 POSIX 命名信号量进行跨进程同步 我注意到进程死亡或退出后 信号量仍然被系统打开 在进程 打开它 死亡或退出后是否有办法使其关闭 释放 早期的讨论在这里 当将信号量递减至零的进程崩溃时 如何恢复信号量 https sta
  • 全局使用和 .NET Standard 2.0

    我最近意识到我可以使用 C 10 功能文件范围的命名空间在 NET Standard 2 0 项目中也可以通过设置
  • 带有运算符语法的错误消息,但不带有函数语法的错误消息

    为什么我在调用 unary 时收到错误消息 使用运算符语法 如果我用函数语法调用它就可以了 现场演示 https godbolt org z j7AbeQ template
  • 如何使用 Roslyn 通过扩展方法、静态类中的方法以及带有 ref/out 参数的方法来访问调用

    我正在致力于创建一个开源项目 用于创建 NET UML 序列图 该项目利用名为 js sequence diagrams 的 javascript 库 我不确定 Roslyn 是适合这项工作的工具 但我想我应该尝试一下 所以我整理了一些概念
  • 使用 C# 中的 Google 地图 API 和 SSIS 包获取行驶距离

    更新 找到了谷歌距离矩阵并尝试相应地修改我的代码 我在这里收到无效参数错误 return new GeoLocation dstnc uri ToString catch return new GeoLocation 0 0 https 基
  • Resharper:IEnumerable 的可能多重枚举

    我正在使用新的 Resharper 版本 6 在我的代码中的几个地方 它给一些文本加了下划线 并警告我可能存在IEnumerable 可能的多重枚举 我理解这意味着什么 并在适当的情况下采纳了建议 但在某些情况下 我不确定这实际上是一个大问
  • 为什么不能调用带有 auto& 参数的 const mutable lambda?

    include
  • 使用多线程进行矩阵乘法?

    我应该使用线程将两个矩阵相乘 有两件事 当我运行程序时 我不断得到 0 我还收到消息错误 对于每个错误 它在粗体行上显示 警告 从不兼容的指针类型传递 printMatrix 的参数1 我尝试打印输出 还要注意 第一个粗体块 这是我解决问题
  • 使用 xslt 将 xml 转换为 xsl-fo 时动态创建超链接?

    我想使用 xsl 文件在 PDF 报告中创建标题 如果源文件包含超链接 则应将其呈现为超链接 否则呈现为纯文本 例如 我的 xml 如下所示 a href http google com target blank This is the h
  • C 中使用 getrandom 实现随机浮点数

    我试图生成一个介于 0 和 1 之间的随机浮点数 无论是在 0 1 还是 0 1 对我来说都不重要 网上关于此的每个问题似乎都涉及rand 呼叫 播种time NULL 但我希望能够每秒多次调用我的程序 并每次都获得不同的随机数 这引导我找
  • 浮点字节序?

    我正在为实时海上模拟器编写客户端和服务器 并且由于我必须通过套接字发送大量数据 因此我使用二进制数据来最大化可以发送的数据量 我已经了解整数字节顺序以及如何使用htonl and ntohl为了规避字节顺序问题 但我的应用程序与几乎所有模拟
  • Xamarin.Forms UWP 项目中标题栏和选项卡之间令人恼火的空白

    我几乎是新手Xamarin Forms我正在开发一个相当简单的跨平台应用程序 该应用程序在 Android 中显示得足够好 但在 UWP 中却出现了一个愚蠢的空白 该项目由一个 TabbedPage 组成 其中包含 4 个 Navigati
  • 深度估计的准确性 - 立体视觉

    我正在研究立体视觉 我对这个问题的深度估计的准确性感兴趣 这取决于几个因素 例如 适当的立体校准 旋转 平移和失真提取 图像分辨率 相机和镜头质量 失真越小 色彩捕捉正确 两个图像之间的匹配特征 假设我们没有低成本的相机和镜头 没有廉价的网
  • 如何在c linux中收听特定接口上的广播?

    我目前可以通过执行以下操作来收听我编写的简单广播服务器 仅广播 hello int fd socket PF INET SOCK DGRAM 0 struct sockaddr in addr memset addr 0 sizeof ad
  • C++ Boost ASIO 简单的周期性定时器?

    我想要一个非常简单的周期性计时器每 50 毫秒调用我的代码 我可以创建一个始终休眠 50 毫秒的线程 但这很痛苦 我可以开始研究用于制作计时器的 Linux API 但它不可移植 I d like使用升压 我只是不确定这是否可能 boost

随机推荐