Shift image content with OpenCV

后端 未结 9 1146
-上瘾入骨i
-上瘾入骨i 2020-12-08 04:36

Starting from an image, I would like to shift its content upward of 10 pixels, without changing size and filling in black the sub image (width x 10px) on the bo

相关标签:
9条回答
  • 2020-12-08 04:58

    Is there a function to perform directly this operation with OpenCV?

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

    or you would do this

        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)));
    
    0 讨论(0)
  • 2020-12-08 04:58

    My implementation uses the same as the accepted answer however it can move in any direction...

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

    It's taken from my own working code but some variables changed, if it doesn't compile, very likely just a small thing needs changing - but you get the idea re. the abs function...

    0 讨论(0)
  • 2020-12-08 05:01

    I first tried with pajus_cz's answer, but it was quite slow in practice. Also, I cannot afford to make a temporary copy, so I came up with this:

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

    It's orders of magnitude faster than the warpAffine-based solution. (But this of course may be completely irrelevant in your case.)

    0 讨论(0)
  • 2020-12-08 05:06

    You can simply use affine transformation translation matrix (which is for shifting points basically). cv::warpAffine() with proper transformation matrix will do the trick.

    TranslationMatrix [1,0,tx ; 0,1,ty]

    where: tx is shift in the image x axis, ty is shift in the image y axis, Every single pixel in the image will be shifted like that.

    You can use this function which returns the translation matrix. (That is probably unnecessary for you) But it will shift the image based on offsetx and offsety parameters.

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

    In your case - you want to shift image 10 pixels up, you call:

    translateImg(image,0,-10);
    

    And then your image will be shifted as you desire.

    0 讨论(0)
  • 2020-12-08 05:08

    this link maybe help this question, thanks

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

    and tx and ty could control the shift pixels on x and y direction respectively.

    0 讨论(0)
  • 2020-12-08 05:09

    You can use a simple 2d filter/convolution to achieve your goal:

    Taken straight from the OpenCV documentation. You will need to filter with a kernel that has height (desired_displacement_y * 2 + 1) and width (desired_displacement_x * 2 + 1).

    Then you will need to set the kernel to all zeros except for the relative pixel position from where you want to copy. So if your kernel center is (0,0) you would set (10,0) to 1 for a displacement of 10 pixels.

    Take the sample code from the website, and replace the kernel code in the middle with the following:

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

    Notice BORDER_CONSTANT in filter2D! You should now run the example and have a the picture scroll up by one pixel every 0.5 seconds. You could also draw the black pixels using drawing methods.

    On why this works, see Wikipedia.

    0 讨论(0)
提交回复
热议问题