【问题标题】:Need to copy one image to another image ROI需要将一张图像复制到另一张图像 ROI
【发布时间】:2023-04-03 06:53:01
【问题描述】:

我正在尝试将一个图像层复制到另一个图像 ROI。我的代码如下。

Mat4b src= imread("path");
Mat3b dest = imread("path");
Rect roi = Rect(179,539,src.cols,src.rows); //src.cols = 1186 and src.rows= 1134 after scaling.
Mat destinationROI = dest(roi);
src.copyTo(destinationROI);
imwrite("destinationROI.png", destinationROI);

输入的src是 输入目标是

但得到的输出是相同的目标图像。 然后我尝试在复制之前保存destinationROI。我得到的输出是,这是正确的。复制 src 也可以。但它不会对目标图像产生任何影响。

【问题讨论】:

    标签: c++ opencv image-processing


    【解决方案1】:

    这是为了确认@ypnos 有根据的猜测 是正确的(好话,顺便说一句)。


    看看这段代码,它执行的操作与你的相同:

    #include <opencv2\opencv.hpp>
    #include <iostream>
    using namespace cv;
    using namespace std;
    
    
    int main()
    {
        Mat4b m4b(50, 50, Vec4b(0, 255, 0, 255));   // blue image, 4 channels
        Mat3b m3b(100, 100, Vec3b(255, 0, 0));      // green image, 3 channels
    
        cout << "After init:" << endl;
        cout << "m4b channels: " << m4b.channels() << endl;
        cout << "m3b channels: " << m3b.channels() << endl << endl;
    
        Rect roi(0, 0, 50, 50); // roi
    
        // Create a new header for the data inside the roi in m3b
        // No data copied, just a new header.
        // So destRoi has same number of channels of m3b
        Mat destRoi = m3b(roi); 
    
    
        cout << "After roi:" << endl;
        cout << "m4b channels    : " << m4b.channels() << endl;
        cout << "m3b channels    : " << m3b.channels() << endl;
        cout << "destRoi channels: " << destRoi.channels() << endl << endl;
    
        // destination type != source type
        // destRoi is newly created with the destination type
        // destRoi doesn't point anymore to the data in m3b and has 4 channels now
        m4b.copyTo(destRoi);
    
        cout << "After copyTo:" << endl;
        cout << "m4b channels    : " << m4b.channels() << endl;
        cout << "m3b channels    : " << m3b.channels() << endl;
        cout << "destRoi channels: " << destRoi.channels() << endl << endl;
    
        return 0;
    }
    

    输出:

    After init:
    m4b channels: 4
    m3b channels: 3
    
    After roi:
    m4b channels    : 4
    m3b channels    : 3
    destRoi channels: 3
    
    After copyTo:
    m4b channels    : 4
    m3b channels    : 3
    destRoi channels: 4
    

    解决方案

    使用具有相同通道数的两个矩阵,方法是:

    1. 将两个图像加载为 3 通道矩阵 CV_8UC3其实你发的图片都是3个频道

    2. 使用cvtColor 转换为相同数量的通道,然后再执行 roi 和复制操作。

    【讨论】:

    • 非常有帮助的调查!
    • @Miki 我将所有输入图像更改为 Mat img = imread("path",CV_8UC3)。然后也有eroor。错误来自 Mat.hpp ..... inline Mat Mat::operator()(const Range* range) const { return Mat(*this, range); }
    • @Miki 请看shrib.com/4BMXuPSVCsrKRLF?v=nc。有什么我做错了吗?
    • 几点注意事项:1) 将代码编辑到问题中,2) 名为Point 的结构很可能与cv::Point 发生冲突,因此请更改名称。另外,你为什么不首先使用std::vector&lt;cv::Point&gt;? 3) CV_8UC3 不是imread 的有效参数。您应该使用IMREAD_COLORCV_LOAD_IMAGE_COLOR(相同) 4)应用这些更改并让我知道
    • @Miki 我完成了这些更改。更改了我的结构名称。 (仅用于测试。稍后点数据将从kinect获得)。现在还有未处理的异常......它来自内联 Mat Mat::operator()( const Rect& roi ) const { return Mat(*this, roi); }.. 我也在 shrib.com/4BMXuPSVCsrKRLF?v=nc 中编辑过
    【解决方案2】:

    您的矩阵类型不匹配。一个有四个通道,另一个有三个。 显然,将4通道矩阵的内容复制到3通道矩阵中是行不通的。

    不幸的是,在某些情况下,当 OpenCV 无法在旧内存上工作时,它会默默地回退到创建新矩阵。最有可能的是,这种情况。执行复制后,destinationROI 开始指向新内存。

    请注意,您可以通过将destinationROI 声明为Mat3b 来防止这种行为。但是,要使您的代码正常工作,源和目标都需要携带相同数量的通道。

    我在这里所做的两个假设都只是有根据的猜测,我没有测试有问题的代码。

    【讨论】:

    • 我之前尝试将格式更改为 Mat3b。但是当我这样做时,我遇到了错误。我不知道为什么...
    • 您是否阅读了我的修改,“但是,要使您的代码正常工作,源和目标都需要携带相同数量的通道。”?
    • 是的,我尝试将所有图像更改为 Mat3b,然后更改为 Mat4b,然后更改为 Mat.. 但每次我遇到错误... :(
    • 也许您应该向我们展示代码和错误消息,以便我们提供帮助?
    【解决方案3】:

    您的代码太初始了。你的图像也不适合完美的结果。猜猜你在图像上执行了真正的代码,你会得到谁穿衬衫的图像。

    Mat4b src= imread("path");// to load 4 channel image : imread("path",IMREAD_UNCHANGED); 
    Mat3b dest = imread("path");
    Rect roi = Rect(179,539,src.cols,src.rows); //src.cols = 1186 and src.rows= 1134 after scaling.
    Mat destinationROI = dest(roi);
    src.copyTo(destinationROI);
    imwrite("destinationROI.png", destinationROI);
    

    我可以编写代码来获取以下图像(它只是为了显示结果而进行了 photoshop 处理),但它对您的图像毫无意义。

    编辑 1:

    我在这里稍微编辑了您的代码。看看 //edit 1,2,3 里面的代码。

    #include <opencv2/imgproc/imgproc.hpp>
    #include <opencv2/opencv.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <stdio.h>
    
    using namespace cv;
    using namespace std;
    
    float sx, sy;
    int tx, ty;
    
    struct TaggingPoint{
    int rshx, rshy;
    int lshx, lshy;
    int topx, topy;
    int botx, boty;
    }body_points, garment_points;
    
    int main(int argc, char** argv)
    {
    
    Mat shirt;
    Mat body;
    
    shirt = imread(argv[1], IMREAD_COLOR);
    if (shirt.empty())
    return -1;
    
    body = imread(argv[2], IMREAD_COLOR);
    if (body.empty())
    return -1;
    
    body_points.rshx = 418;
    body_points.rshy = 706;
    body_points.lshx = 1234;
    body_points.lshy = 706;
    body_points.topx = 838;
    body_points.topy = 510;
    body_points.botx = 838;
    body_points.boty = 1534;
    
    garment_points.rshx = 239;
    garment_points.rshy = 147;
    garment_points.lshx = 755;
    garment_points.lshy = 147;
    garment_points.topx = 505;
    garment_points.topy = 50;
    garment_points.botx = 505;
    garment_points.boty = 953;
    
    
    // edit 1 : when you calculate by this values your shirt image's width will be greater that body image's width
    // so to reduce it
    sx = (float)(body_points.lshx - body_points.rshx) / (garment_points.lshx - garment_points.rshx)*0.995;
    sy = (float)(body_points.boty - body_points.topy) / (garment_points.boty - garment_points.topy);
    
    //scale the image
    resize(shirt, shirt, Size(), sx, sy, INTER_LINEAR);
    
    imwrite("shirt.png", shirt);
    
    //translation happened
    //  tx = body_points.rshx - (sx * garment_points.rshx);
    tx = body_points.rshx - (garment_points.rshx);
    ty = body_points.rshy - (sy * garment_points.rshy);
    
    //draw one image over another image
    //src.copyTo(dst.rowRange(1, 6).colRange(3, 10));
    //  shirt.copyTo(body.rowRange(tx, shirt.rows).colRange(ty, shirt.cols));
    //  shirt.copyTo(body.rowRange(100, 1000).colRange(100, 500));
    
    //  cvtColor(shirt, shirt, CV_BGRA2BGR);
    //  cvtColor(body, body, CV_BGRA2BGR);
    
    
    namedWindow("body");
    //Rect roi(cv::Point(tx, ty), Size(shirt.size()));
    
    // Edit 2 : Rect.x = 0
    
    Rect roi = Rect(0,ty,shirt.cols,shirt.rows);
    Mat destinationROI = body(roi);
    //  cvtColor(destinationROI, destinationROI, CV_BGRA2BGR);
    
    // Edit 3 : Create a mask ( it is show purpose only, need improvement )
    Mat mask;
    cvtColor( shirt, mask, COLOR_BGR2GRAY );
    mask = mask < 250;
    
    shirt.copyTo(destinationROI,mask);
    
    imwrite("destinationROI.png", destinationROI);
    
    imshow("body", body);
    imwrite("body.png", body);
    
    waitKey();
    return 0;
    }
    

    【讨论】:

    • 我不认为像“使用 Photoshop”这样的答案在这里有用。还要解释为什么您的代码有效,以及 OP 的代码有什么问题。
    • 代码没有真正的区别。他只是换了一条线,但没有解决问题。
    • "它被 photoshopped 只是为了显示结果"猜我写了代码,你得到了这个图像。我的意思是它没用。
    • 如果您需要进一步的帮助,请在 OpenCV 官方Q/A 论坛上提问。
    猜你喜欢
    • 1970-01-01
    • 2011-05-21
    • 1970-01-01
    • 1970-01-01
    • 2019-04-22
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多