Shift image content with OpenCV

匿名 (未验证) 提交于 2019-12-03 01:10:02

问题:

Starting from an image, I would like to shift its content to the top of 10 pixels, without change the size and filling the sub image width x 10 on bottom with black.

For instance, the original:

And the shifted:

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

回答1:

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


回答2:

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


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_(2,3) 

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.



回答3:

Here is a function I wrote, based on Zaw Lin's answer, to do frame/image shift in any direction by any amount of pixel rows or columns:

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 


回答4:

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

The code above only can be used to shift to one side (to the left, and to the top). Below code is the extended version of above code which can be used to shift into every direction.

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


回答5:

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...



回答6:

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



回答7:

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



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!