【问题标题】:Shift image content with OpenCV使用 OpenCV 移动图像内容
【发布时间】:2013-09-28 14:38:27
【问题描述】:

从一张图片开始,我想将其内容向上移动 10 个像素,不改变大小并将底部的子图片 (width x 10px) 填充为黑色。

比如原文:

还有转移的:

OpenCV有什么函数可以执行这个操作吗?

【问题讨论】:

    标签: c++ opencv


    【解决方案1】:

    您可以简单地使用仿射变换平移矩阵(基本上用于移动点)。 cv::warpAffine() 使用适当的转换矩阵就可以了。


    在哪里: tx 是图像 x 轴的偏移, ty 是图像 y 轴的偏移, 图像中的每个像素都会像这样移动。

    您可以使用此函数返回平移矩阵。 (这对你来说可能是不必要的)但它会根据offsetxoffsety 参数移动图像。

    Mat translateImg(Mat &img, int offsetx, int offsety){
        Mat trans_mat = (Mat_<double>(2,3) << 1, 0, offsetx, 0, 1, offsety);
        warpAffine(img,img,trans_mat,img.size());
        return img;
    }
    

    在你的情况下 - 你想将图像向上移动 10 像素,你打电话:

    translateImg(image,0,-10);
    

    然后你的形象就会随心所欲地变换。

    【讨论】:

    • 你能解释一下Mat_&lt;double&gt;(2,3) &lt;&lt; 1这个语句的作用吗?
    • 不仅仅是Mat_&lt;double&gt;(2,3) &lt;&lt; 1。它是整个表达式:Mat_&lt;double&gt;(2,3) &lt;&lt; 1, 0, offsetx, 0, 1, offsety,它将值插入到矩阵中。所以trans_mat 中的值将是第一行中的1,0,offsetx 和第二行中的0, 1, offsety。如原帖中的矩阵M所示。
    • 创意答案,但与其他解决方案相比,CPU 密集。
    • @pajus_cz 感谢您的澄清
    【解决方案2】:

    有没有直接用OpenCV执行这个操作的函数?

    https://github.com/opencv/opencv/issues/4413(以前 http://web.archive.org/web/20170615214220/http://code.opencv.org/issues/2299)

    或者你会这样做

        cv::Mat out = cv::Mat::zeros(frame.size(), frame.type());
        frame(cv::Rect(0,10, frame.cols,frame.rows-10)).copyTo(out(cv::Rect(0,0,frame.cols,frame.rows-10)));
    

    【讨论】:

    • 这是一个有点讨厌的把戏。它可以工作,但是没有必要创建“零图像”和复制。我相信我使用 affine transformation 的解决方案更干净,性能更好。
    • @pajus_cz,在任何一种情况下都将创建“零图像”,即使您不是自己创建它。此外,copyTo 执行简单的 memcopy 操作,比 wrapAffine 执行的所有复杂操作快得多。
    • 谢谢!对我来说,第二个结果比 wrapAffine 更快。
    • 如果你想把图片下移怎么办 ;)
    【解决方案3】:

    这是我根据 Zaw Lin 的回答编写的一个函数,用于在任意方向上任意数量的像素行或列进行帧/图像移位:

    enum Direction{
        ShiftUp=1, ShiftRight, ShiftDown, ShiftLeft
       };
    
    cv::Mat shiftFrame(cv::Mat frame, int pixels, Direction direction)
    {
        //create a same sized temporary Mat with all the pixels flagged as invalid (-1)
        cv::Mat temp = cv::Mat::zeros(frame.size(), frame.type());
    
        switch (direction)
        {
        case(ShiftUp) :
            frame(cv::Rect(0, pixels, frame.cols, frame.rows - pixels)).copyTo(temp(cv::Rect(0, 0, temp.cols, temp.rows - pixels)));
            break;
        case(ShiftRight) :
            frame(cv::Rect(0, 0, frame.cols - pixels, frame.rows)).copyTo(temp(cv::Rect(pixels, 0, frame.cols - pixels, frame.rows)));
            break;
        case(ShiftDown) :
            frame(cv::Rect(0, 0, frame.cols, frame.rows - pixels)).copyTo(temp(cv::Rect(0, pixels, frame.cols, frame.rows - pixels)));
            break;
        case(ShiftLeft) :
            frame(cv::Rect(pixels, 0, frame.cols - pixels, frame.rows)).copyTo(temp(cv::Rect(0, 0, frame.cols - pixels, frame.rows)));
            break;
        default:
            std::cout << "Shift direction is not set properly" << std::endl;
        }
    
        return temp;
    }
    

    【讨论】:

      【解决方案4】:

      由于目前没有 Python 解决方案,而使用 Python 移动图像的 Google 搜索会将您带到此页面,这里有一个使用 np.roll() 的 Python 解决方案


      沿 x 轴移动

      import cv2
      import numpy as np
      
      image = cv2.imread('1.jpg')
      shift = 40
      
      for i in range(image.shape[1] -1, image.shape[1] - shift, -1):
          image = np.roll(image, -1, axis=1)
          image[:, -1] = 0
      
      cv2.imshow('image', image)
      cv2.waitKey()
      

      沿 y 轴移动

      import cv2
      import numpy as np
      
      image = cv2.imread('1.jpg')
      shift = 40
      
      for i in range(image.shape[0] -1, image.shape[0] - shift, -1):
          image = np.roll(image, -1, axis=0)
          image[-1, :] = 0
      
      cv2.imshow('image', image)
      cv2.waitKey()
      

      【讨论】:

      • np.roll 正是我正在寻找的,即使我不使用图像。谢谢!
      • 如何将其对角移动到右上角。即上移和右移?
      【解决方案5】:

      this link也许能帮到这个问题,谢谢

      import cv2
      import numpy as np
      img = cv2.imread('images/input.jpg')
      num_rows, num_cols = img.shape[:2]   
      
      translation_matrix = np.float32([ [1,0,70], [0,1,110] ])   
      img_translation = cv2.warpAffine(img, translation_matrix, (num_cols, num_rows))   
      cv2.imshow('Translation', img_translation)    
      cv2.waitKey()
      

      txty可以分别控制x和y方向的位移像素。

      【讨论】:

        【解决方案6】:

        有没有直接用OpenCV执行这个操作的函数?

        http://code.opencv.org/issues/2299

        或者你会这样做

          cv::Mat out = cv::Mat::zeros(frame.size(), frame.type());
          frame(cv::Rect(0,10,
          frame.cols,frame.rows-10)).copyTo(out(cv::Rect(0,0,frame.cols,frame.rows-10)));
        

        上面的代码只能用于移动到一侧(向左和向上)。下面的代码是上面代码的扩展版本,可以用来向各个方向移动。

        int shiftCol = 10;
        int shiftRow = 10;
        
        Rect source = cv::Rect(max(0,-shiftCol),max(0,-shiftRow), frame.cols-abs(shiftCol),frame.rows-abs(shiftRow));
        
        Rect target = cv::Rect(max(0,shiftCol),max(0,shiftRow),frame.cols-abs(shiftCol),frame.rows-abs(shiftRow));
        
        frame(source).copyTo(out(target));
        

        【讨论】:

          【解决方案7】:
          h, w = image.shape     # for gray image
          shift = 100          # any legal number 0 < x < h
          
          img[:h-shift, :] = img[shift:, :]
          img[h-shift:, :] = 0
          

          【讨论】:

            【解决方案8】:

            我的实现使用与接受的答案相同的方法,但是它可以向任何方向移动...

            using namespace cv;
            //and whatever header 'abs' requires...
            
            Mat offsetImageWithPadding(const Mat& originalImage, int offsetX, int offsetY, Scalar backgroundColour){
                    cv::Mat padded = Mat(originalImage.rows + 2 * abs(offsetY), originalImage.cols + 2 * abs(offsetX), CV_8UC3, backgroundColour);
                    originalImage.copyTo(padded(Rect(abs(offsetX), abs(offsetY), originalImage.cols, originalImage.rows)));
                    return Mat(padded,Rect(abs(offsetX) + offsetX, abs(offsetY) + offsetY, originalImage.cols, originalImage.rows));
            }
            
            //example use with black borders along the right hand side and top:
            Mat offsetImage = offsetImageWithPadding(originalImage, -10, 6, Scalar(0,0,0));
            

            它取自我自己的工作代码,但一些变量发生了变化,如果它不能编译,很可能只是一个小东西需要改变 - 但你明白了。 abs 函数...

            【讨论】:

              【解决方案9】:

              您可以使用简单的 2d 过滤器/卷积来实现您的目标:

              直接取自the OpenCV documentation。您需要使用具有高度 (desired_displacement_y * 2 + 1) 和宽度 (desired_displacement_x * 2 + 1) 的内核进行过滤。

              然后您需要将内核设置为全零,除了您要复制的相对像素位置。因此,如果您的内核中心为 (0,0),您可以将 (10,0) 设置为 1,以实现 10 像素的位移。

              从网站上获取示例代码,将中间的内核代码替换为以下代码:

                /// Update kernel size for a normalized box filter
                kernel_size = 1 + ind * 2; //Center pixel plus displacement diameter (=radius * 2)
                kernel = Mat::zeros( kernel_size, kernel_size, CV_32F );
                kernel.at<float>(ind * 2, ind) = 1.0f; // Indices are zero-based, not relative
              
                /// Apply filter
                filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_CONSTANT );
              

              注意 filter2D 中的 BORDER_CONSTANT!您现在应该运行该示例并让图片每 0.5 秒向上滚动一个像素。您也可以使用绘图方法绘制黑色像素。

              关于为什么会这样,请参阅Wikipedia

              【讨论】:

              • 创意答案,但 CPU 密集型。请改用 shift 方法。
              【解决方案10】:

              我第一次尝试使用pajus_cz's answer,但在实践中速度很慢。另外,我买不起临时副本,所以我想出了这个:

              void translateY(cv::Mat& image, int yOffset)
              {
                  int validHeight = std::max(image.rows - abs(yOffset), 0);
                  int firstSourceRow = std::max(-yOffset, 0);
                  int firstDestinationRow = std::max(yOffset, 0);
              
                  memmove(image.ptr(firstDestinationRow),
                          image.ptr(firstSourceRow),
                          validHeight * image.step);
              }
              

              它比基于warpAffine 的解决方案快几个数量级。 (但这当然可能与您的情况完全无关。)

              【讨论】:

                【解决方案11】:

                Python 代码有些人可能会觉得有用。

                h, w, c = image.shape 
                shift = 4 #set shift magnitude
                img_shift_right = np.zeros(image.shape)
                img_shift_down = np.zeros(image.shape)
                img_shift_left = np.zeros(image.shape)
                img_shift_up = np.zeros(image.shape)
                
                
                
                img_shift_right[:,shift:w, :] = image[:,:w-shift, :]
                img_shift_down[shift:h, :, :] = image[:h-shift, :, :]
                img_shift_left[:,:w-shift, :] = image[:,shift:, :]
                img_shift_up[:h-shift, :, :] = image[shift:, :, :]
                

                【讨论】:

                  猜你喜欢
                  • 2016-02-18
                  • 2021-09-17
                  • 2021-12-29
                  • 1970-01-01
                  • 2018-04-17
                  • 2011-10-24
                  • 2020-12-10
                  • 2017-04-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多