C++ 使用 OpenCV 移动图像内容
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19068085/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Shift image content with OpenCV
提问by vdenotaris
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.
从图像开始,我想将其内容移动到 10 个像素的顶部,而不改变大小并width x 10
用黑色填充底部的子图像。
For instance, the original:
比如原文:
And the shifted:
和转移:
Is there a function to perform directly this operation with OpenCV?
有没有直接用 OpenCV 执行这个操作的函数?
采纳答案by Zaw Lin
Is there a function to perform directly this operation with OpenCV?
有没有直接用 OpenCV 执行这个操作的函数?
http://code.opencv.org/issues/2299
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)));
回答by pajus_cz
You can simply use affine transformation translation matrix (which is for shifting points basically). cv::warpAffine()
with proper transformation matrix will do the trick.
您可以简单地使用仿射变换平移矩阵(基本上用于移动点)。cv::warpAffine()
使用适当的转换矩阵就可以解决问题。
where: txis shift in the image x axis, tyis shift in the image y axis, Every single pixel in the image will be shifted like that.
其中: tx是图像 x 轴的位移, ty是图像 y 轴的位移,图像中的每个像素都将像这样位移。
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.
您可以使用此函数返回平移矩阵。(这对您来说可能是不必要的)但它会根据offsetx
和offsety
参数移动图像。
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:
在您的情况下 - 您想将图像向上移动 10 个像素,您可以调用:
translateImg(image,0,-10);
And then your image will be shifted as you desire.
然后你的形象会按照你的意愿改变。
回答by Antonis Io
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:
这是我根据 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;
}
回答by William Sutrisna
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)));
有没有直接用 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)));
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));
回答by nathancy
Since there's currently no Python solution and a Google search for shifting an image using Python brings you to this page, here's an Python solution using np.roll()
由于目前没有 Python 解决方案,并且 Google 搜索使用 Python 移动图像会将您带到此页面,因此这里有一个使用 Python 的解决方案 np.roll()
Shifting against x-axis
相对于 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()
Shifting against y-axis
相对于 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()
回答by J.Zhao
this linkmaybe 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 txand tycould control the shift pixels on x and y direction respectively.
并且tx和ty可以分别控制 x 和 y 方向上的移位像素。
回答by Lamar Latrell
My implementation uses the same as the accepted answer however it can move in anydirection...
我的实现使用与接受的答案相同的方法,但是它可以向任何方向移动......
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 absfunction...
它取自我自己的工作代码,但一些变量发生了变化,如果它不能编译,很可能只是一件小事需要改变——但你明白了。在ABS功能...
回答by Reunanen
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:
我首先尝试使用pajus_cz 的答案,但在实践中速度很慢。另外,我负担不起制作临时副本的费用,所以我想出了这个:
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.)
它比warpAffine
基于的解决方案快几个数量级。(但这当然可能与您的情况完全无关。)
回答by FRob
You can use a simple 2d filter/convolution to achieve your goal:
您可以使用简单的 2d 过滤器/卷积来实现您的目标:
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).
直接取自OpenCV 文档。您将需要使用具有高度 (desired_displacement_y * 2 + 1) 和宽度 (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.
然后,除了要复制的相对像素位置之外,您需要将内核设置为全零。因此,如果您的内核中心是 (0,0),您会将 (10,0) 设置为 1 以表示 10 个像素的位移。
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.
注意 filter2D 中的 BORDER_CONSTANT!您现在应该运行该示例并让图片每 0.5 秒向上滚动一个像素。您还可以使用绘图方法绘制黑色像素。
On why this works, see Wikipedia.
关于为什么会这样,请参阅Wikipedia。