I am trying to translate an image horizontally by x pixels and vertically by y pixels, so . However, I want the pixels to wrap around the edges. Basically...
As far as I know, OpenCv's warpAffine() is not capable of doing this. Normally, I would just loop through the image and shift the pixels a certain amount, but in doing this I can only shift them horizontally. What is the most efficient way to go about this?
From my point of view, the most "efficient" way would be to set up the four corresponding ROIs by using cv::Rect
, and manually copying the contents using cv::copyTo
. Maybe, there's also a possibility without copying the actual content, just pointing to the data in the input cv::Mat
- but unfortunately, at least I couldn't found one.
Nevertheless, here's my code:
// Shift input image by sx pixels to the left, and sy pixels to the top.
cv::Mat transWrap(cv::Mat& input, const int sx, const int sy)
{
// Get image dimensions.
const int w = input.size().width;
const int h = input.size().height;
// Initialize output with same dimensions and type.
cv::Mat output = cv::Mat(h, w, input.type());
// Copy proper contents manually.
input(cv::Rect(sx, sy, w - sx, h - sy)).copyTo(output(cv::Rect(0, 0, w - sx, h - sy)));
input(cv::Rect(0, sy, sx, h - sy)).copyTo(output(cv::Rect(w - sx, 0, sx, h - sy)));
input(cv::Rect(sx, 0, w - sx, sy)).copyTo(output(cv::Rect(0, h - sy, w - sx, sy)));
input(cv::Rect(0, 0, sx, sy)).copyTo(output(cv::Rect(w - sx, h - sy, sx, sy)));
return output;
}
int main()
{
cv::Mat input = cv::imread("images/tcLUa.jpg", cv::IMREAD_COLOR);
cv::resize(input, input, cv::Size(), 0.25, 0.25);
cv::Mat output = transWrap(input, 300, 150);
return 0;
}
Of course, the code seems repetitive, but wrapped into an own function, it won't bother you in your main code. ;-)
The output should be, what you want to achieve:
Hope that helps!