【问题标题】:Passing IplImage * to function, original not getting updated将 IplImage * 传递给函数,原始未更新
【发布时间】:2013-02-10 16:42:41
【问题描述】:

我在函数中传递 IplImage* 参数时遇到问题。这是一个学校项目,不幸的是,我不应该编辑调用我的过滤器函数的文件。主要是将图像作为命令行参数引入,然后制作一个副本并将其传递给正确的过滤器函数,如下所示:

IplImage * floating = cvCreateImage (cvSize (img->width, img->height), IPL_DEPTH_32F, 3);
cvConvertScale (img, floating, 1/255., 0);

IplImage * filtered;

switch (filter.ImageFormat)
{
    case YUV24:
        filtered = cvCreateImage (cvSize (floating->width, floating->height), IPL_DEPTH_32F, 3);
        cvCvtColor (floating, filtered, CV_BGR2YCrCb);
        break;
    case BGR24:
        filtered = cvCloneImage (floating);
        break;
    case Gray:
        filtered = cvCreateImage (cvSize (floating->width, floating->height), IPL_DEPTH_32F, 1);
        cvCvtColor (floating, filtered, CV_BGR2GRAY);
        break;
}

cvNamedWindow ("original", CV_WINDOW_AUTOSIZE);
cvShowImage ("original", img);

filter.ImageFilter (filtered, p);

if (filter.ImageFormat == YUV24)
{
      cvCvtColor (filtered, filtered, CV_YCrCb2BGR);
}

cvNamedWindow (filterName.c_str(), CV_WINDOW_AUTOSIZE);
cvShowImage (filterName.c_str(), filtered);

这是来自我的一个过滤器的代码:

void median (IplImage * image, int k){
    cout << "image address: " << &image << endl;
    Mat matImage(image);        //convert IplImage to Mat for work
    vector<Mat> bgr_channels;   //vector to hold each channel
    int i,j,m,n;                //row/column indeces
    int kernelSize = (2*k+1)*(2*k+1);
    vector<float> vals(kernelSize); //kernelSized vector to hold all values of image
                //within kernel centered at a given pixel
    int vecIndex = 0;   //then sorted to get the median
    int chanIndex = 0;  //index used to for each channel

    //add padding to account for border issues with convolution
    copyMakeBorder( matImage, matImage, k, k, k, k, BORDER_REPLICATE);
    //split channes to do work on individual channels
    split(matImage, bgr_channels);

    for(chanIndex=0; chanIndex < matImage.channels(); chanIndex++){
        //outer loop for scanning entire image
        for(i=k; i<matImage.rows-k; i++)/*image row index*/{
            for(j=k; j<matImage.cols-k; j++)/*image column index*/{
                //inner loop for scanning image only in kernel boundaries
                vecIndex = 0;   //reset vecIndex at start of each kernel loop
                for(m=i-k; m<(i+k+1); m++)/*kernel row index*/{
                    for(n=j-k; n<(j+k+1); n++)/*kernel column index*/{                      
                        vals[vecIndex++] = bgr_channels[chanIndex].at<float>(m,n);
                    }
                }
                insertionSort(vals, 0, vals.size()-1);  //insertion sort from CSCI362 text, see references  
                bgr_channels[chanIndex].at<float>(i,j) = vals[vals.size()/2]; //new value chosen from middle element                                                                //of sorted vector
            }
        }
    }

    merge(bgr_channels, matImage);      //merge channels together
    imshow("Median: Mat", matImage);    //left this in becuase the original doesn't seem to get modified    
                                        //when converting the Mat back to an IplImage
    image = cvCloneImage(&(IplImage)matImage);  //convert backto IplImage for DesktopMain
}

问题是,主要显示的过滤图像不反映实际图像。它只显示原始图像。当我将 Mat 风格的图像 matImage 输出到我的过滤器函数中时,它会显示过滤后的图像。在我转换回 IplImage 并将 IplImage* 输入参数设置为等于转换后的过滤版本之后立即。但这些变化并没有反映主函数中显示的图像。

这使得我很难创建其他一些过滤器,例如 Gaussian 和 Sobel,因为这些过滤器本身会在进行操作之前调用其他函数,而我无法取回已编辑的数据。我在如何编辑传递的 IplImage* 变量时缺少什么?

提前感谢您的帮助!

【问题讨论】:

    标签: c++ c opencv parameter-passing iplimage


    【解决方案1】:

    您的函数永远不会编辑传递给它的图像。

    这行大概是在复制图像。

    Mat matImage(image);        //convert IplImage to Mat for work
    

    然后您的代码会修改 matImage 副本。

    在函数结束时,该本地副本被销毁,image 指向的IplImage 从未被修改过。

    编辑: Vaughn Cato 的回答具体说明了如何解决这个问题。

    【讨论】:

      【解决方案2】:

      而不是这个:

      image = cvCloneImage(&(IplImage)matImage); 
      

      使用这个:

      cvCopy(&(IplImage)matImage,image);
      

      【讨论】:

      • 是的,效果很好。最初有一些问题,因为我已经填充了 matImage 的边框,但是去掉了它并且效果很好。出于好奇,并且需要了解,以上两者有什么区别。两者似乎都在 IplImage* 图像上运行。如果我在 cvCloneImage 调用之后立即执行 cvShowImage("image", image),我会看到过滤后的版本。为什么这些对图像的更改不会像 cvCopy 那样影响来自 main 的图像?非常感谢您的帮助!
      • @JoshPharis:您正在按值传递参数,即指针的 copy 被传递给函数。这意味着您可以改变 指针所指的内容 并且该突变将在函数外部看到,但是如果您为参数分配一个全新的值,您只是修改传递给的副本功能。 C 中的所有参数都是按值传递的,而在 C++ 中,当您使用类似的东西时,您会通过引用传递; void foo(SomeType&amp; arg);
      【解决方案3】:

      要遍历 3 个通道,您应该使用迭代器:

      Mat out;
      *********open out********
      Mat_<Vec3b>::iterator it = out.begin<Vec3b>();
      MatConstIterator_<Vec3b> it_end = out.end<Vec3b>();
      
      for(; it != it_end; ++it)
      {
          //your 3 channels
          (*it)[0] = ...;
          (*it)[1] = ....;
          (*it)[2] = ......;
      }
      

      【讨论】:

        猜你喜欢
        • 2012-11-25
        • 2015-04-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-02
        相关资源
        最近更新 更多