Shift image content with OpenCV - c++

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 bottom.
For instance, the original:
And the shifted:
Is there any function to perform this operation with OpenCV?

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

Is there a function to perform directly this operation with OpenCV?
https://github.com/opencv/opencv/issues/4413 (previously
http://web.archive.org/web/20170615214220/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)));

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.

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 << "Shift direction is not set properly" << std::endl;
}
return temp;
}

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()
Shifting against x-axis
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
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()

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

h, w = image.shape # for gray image
shift = 100 # any legal number 0 < x < h
img[:h-shift, :] = img[shift:, :]
img[h-shift:, :] = 0

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

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.

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

Python code some might find useful.
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:, :, :]

Related

OpenCv: Translate Image, Wrap Pixels Around Edges (C++)

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...
we start with image one...
shift by x pixels...
and shift by y pixels...
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?
You can use np.roll()
Here's a visualization
I implemented it in Python but you can apply a similar rolling technique in C++
import cv2
import numpy as np
image = cv2.imread('1.jpg')
shift_x = 800
shift_y = 650
# Shift by x-axis
for i in range(image.shape[1] -1, shift_x, -1):
image = np.roll(image, -1, axis=1)
image[:, -1] = image[:, 0]
cv2.imshow('image', image)
cv2.waitKey(1)
# Shift by y-axis
for i in range(image.shape[1] -1, shift_y, -1):
image = np.roll(image, -1, axis=0)
image[:, -1] = image[:, 0]
cv2.imshow('image', image)
cv2.waitKey(1)
cv2.imshow('image', image)
cv2.waitKey()
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!

OpenCV Image shift [duplicate]

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 bottom.
For instance, the original:
And the shifted:
Is there any function to perform this operation with OpenCV?
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_<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.
Is there a function to perform directly this operation with OpenCV?
https://github.com/opencv/opencv/issues/4413 (previously
http://web.archive.org/web/20170615214220/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)));
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.
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 << "Shift direction is not set properly" << std::endl;
}
return temp;
}
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()
Shifting against x-axis
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
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()
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));
h, w = image.shape # for gray image
shift = 100 # any legal number 0 < x < h
img[:h-shift, :] = img[shift:, :]
img[h-shift:, :] = 0
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...
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.
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.)
Python code some might find useful.
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:, :, :]

What does the gradient from Sobel mean?

I have the gradients from the Sobel operator for each pixel. In my case 320x480. But how can I relate them with the orientation? For an example, I'm planning to draw an orientation map for fingerprints. So, how do I start?
Is it by dividing the gradients into blocks (example 16x24) then adding the gradients together and diving it by 384 to get the average gradients? Then from there draw a line from the center of the block using the average gradient?
Correct me if i'm wrong. Thank you.
Here are the codes that i used to find gradients
cv::Mat original_Mat=cv::imread("original.bmp", 1);
cv::Mat grad = cv::Mat::zeros(original_Mat.size(), CV_64F);
cv::Mat grad_x = cv::Mat::zeros(original_Mat.size(), CV_64F);
cv::Mat grad_y = cv::Mat::zeros(original_Mat.size(), CV_64F);
/// Gradient X
cv::Sobel(original_Mat, grad_x, CV_16S, 1, 0, 3);
/// Gradient Y
cv::Sobel(original_Mat, grad_y, CV_16S, 0, 1, 3);
short* pixelX = grad_x.ptr<short>(0);
short* pixelY = grad_y.ptr<short>(0);
int count = 0;
int min = 999999;
int max = -1;
int a=0,b=0;
for(int i = 0; i < grad_x.rows * grad_x.cols; i++)
{
double directionRAD = atan2(pixelY[i], pixelX[i]);
int directionDEG = (int)(180 + directionRAD / CV_PI * 180);
//printf("%d ",directionDEG);
if(directionDEG < min){min = directionDEG;}
if(directionDEG > max){max = directionDEG;}
if(directionDEG < 0 || directionDEG > 360)
{
cout<<"Weird gradient direction given in method: getGradients.";
}
}
There are several ways to visualize an orientation map:
As you suggested, you could draw it block-wise, but then you would have to be careful about "averaging" the directions. For example, what happens if you average the directions 0° and 180°?
More commonly, the direction is simply mapped to a grey value. This would visualize the gradient per pixel. For example as:
int v = (int)(128+directionRAD / CV_PI * 128);
(Disclaimer: not 100% sure about the 128, one of them might actually have to be a 127...
Or you could map the x and y gradient magnitudes to the rand gcomponents, respectively, ideally after normalizing the gradient vector to length 1. Assuming normX to be the normalized gradient in the x direction with values between -1 and 1:
int red = (int)((normX + 1)*127.5);
int green= (int)((normY + 1)*127.5);
Averaging depends on Sobel kernel size.
It'll be better to use CV_32FC or CV_64FC instead of CV_16S for results.
Also you can speed up your code using cv::phase method.
see my answer here: Sobel operator for gradient angle

OpenCV warping image based on calcOpticalFlowFarneback

I'm trying to perform a complex warp of an image using Dense Optical Flow. I am trying to warp the second image into roughly the same shape as the first image.
cv::Mat flow;
cv::calcOpticalFlowFarneback( mGrayFrame1, mGrayFrame2, flow, 0.5, 3, 15, 3, 5, 1.2, 0 );
cv::Mat newFrame = cv::Mat::zeros( frame.rows, frame.cols, frame.type() );
cv:remap( frame, newFrame, flow, cv::Mat(), CV_INTER_LINEAR );
I calculate the flow from two grayscale frames. I am now trying to remap my original (i.e. non-grayscale) image using this flow information using the cv::remap function. However, I get a very badly distorted image from it. I simply end up with an orange and black image that bears a small resemblance to my original image.
How do I use cv::remap with the calculated flow?
The remap function cannot work with flow directly. One must use a separate map that is computed by taking the backwards flow (from frame2 to frame1) and then offsetting each flow vector by its (x, y) location on the pixel grid. See details below.
Recall the backwards optical flow formula:
frame1(x, y) = frame2(x + flowx(x, y), y + flowy(x, y))
The remap function transforms the source image using a specified map:
dst(x, y) = src(mapx(x, y), mapy(x, y))
Comparing the two equations above, we may determine the map that remap requires:
mapx(x, y) = x + flowx(x, y)
mapy(x, y) = y + flowy(x, y)
Example:
Mat flow; // backward flow
calcOpticalFlowFarneback(nextFrame, prevFrame, flow);
Mat map(flow.size(), CV_32FC2);
for (int y = 0; y < map.rows; ++y)
{
for (int x = 0; x < map.cols; ++x)
{
Point2f f = flow.at<Point2f>(y, x);
map.at<Point2f>(y, x) = Point2f(x + f.x, y + f.y);
}
}
Mat newFrame;
remap(prevFrame, newFrame, map);
Here is a Python solution to warp image from optical flow:
import cv2
import numpy as np
def warp_flow(flow, img1=None, img2=None, interpolation=cv2.INTER_LINEAR):
"""Use remap to warp flow, generating a new image.
If img1 is input, the output will be img2_warped, but there will be multiple pixels corresponding to a single pixel, resulting in sparse holes.
If img2 is input, the output will be img1_warped, and there will be no sparse holes. The latter approach is preferred.
Args:
flow (np.ndarray): flow
img1 (np.ndarray, optional): previous frame
img2 (np.ndarray, optional): next frame
Returns:
warped image"
"""
h, w, _ = flow.shape
remap_flow = flow.transpose(2, 0, 1)
remap_xy = np.float32(np.mgrid[:h, :w][::-1])
if img1 is not None:
uv_new = (remap_xy + remap_flow).round().astype(np.int32)
mask = (uv_new[0] >= 0) & (uv_new[1] >= 0) & (uv_new[0] < w) & (uv_new[1] < h)
uv_new_ = uv_new[:, mask]
remap_xy[:, uv_new_[1], uv_new_[0]] = remap_xy[:, mask]
remap_x, remap_y = remap_xy
img2_warped = cv2.remap(img1, remap_x, remap_y, interpolation)
mask_remaped = np.zeros((h, w), np.bool8)
mask_remaped[uv_new_[1], uv_new_[0]] = True
img2_warped[~mask_remaped] = 0
return img2_warped
elif img2 is not None:
remap_x, remap_y = np.float32(remap_xy + remap_flow)
return cv2.remap(img2, remap_x, remap_y, interpolation)
img1 = cv2.imread("img1.jpg")
img2 = cv2.imread("img2.jpg")
flow = cv2.calcOpticalFlowFarneback(
img1.mean(-1), img2.mean(-1), None, 0.5, 3, 15, 3, 5, 1.2, 0
)
img2_warped = warp_flow(flow, img1=img1)
img1_warped = warp_flow(flow, img2=img2)
cv2.imwrite("warped.jpg", np.vstack([img1_warped, img2_warped]))
cv2.imwrite("target.jpg", np.vstack([img1, img2]))
The examples img1 img2 and flow visualization :
The results warped.jpg target.jpg:

Normalize pixel values between 0 and 1

I am looking to normalize the pixel values of an image to the range [0..1] using C++/OpenCV. However, when I do the normalization using either image *= 1./255 or the normalize function the pixel values are rounded down to zero. I have tried setting the image to type CV_32FC3.
Below is the code I have:
Mat image;
image = imread(imageLoc, CV_LOAD_IMAGE_COLOR | CV_LOAD_IMAGE_ANYDEPTH);
Mat tempImage;
// (didn't work) tempImage *= 1./255;
image.convertTo(tempImage, CV_32F, 3);
normalize(image, tempImage, 0, 1, CV_MINMAX);
int r = 100;
int c = 150;
uchar* ptr = (uchar*)(tempImage.data + r * tempImage.step);
Vec3f tempVals;
tempVals.val[0] = ptr[3*c+1];
tempVals.val[1] = ptr[3*c+2];
tempVals.val[2] = ptr[3*c+3];
cout<<" temp image - "<< tempVals << endl;
uchar* ptr2 = (uchar*)(image.data + r * image.step);
Vec3f imVals;
imVals.val[0] = ptr2[3*c+1];
imVals.val[1] = ptr2[3*c+2];
imVals.val[2] = ptr2[3*c+3];
cout<<" image - "<< imVals << endl;
This produces the following output in the console:
temp image - [0, 0, 0]
image - [90, 78, 60]
You can make convertTo() do the normalization for you:
image.convertTo(tempImage, CV_32FC3, 1.f/255);
You are passing 3 to convertTo(), presumably as channel-count, but that's not the correct signature.
I used the normalize function and it worked (Java):
Core.normalize(src,dst,0.0,1.0,Core.NORM_MINMAX,CvType.CV_32FC1);
You should use a 32F depth for your destination image. I believe the reason for this, is that since you need to get decimal values, you should use an a non-integer OpenCV data type. According to this table, the float types correspond to the 32F depth. I chose the number of channels to be 1 and it worked; CV_32FC1
Remember also that it's unlikely to spot any visual difference in the image.
Finally, since you probably have thousands of pixels in your image, your console might seem that it's printing only zeros. However due to the large amount of data, try to use CTRL+F to see what's going on. Hope this helps.