Replicate OpenCV resize with bilinar interpolation in C (shrink only) - opencv

I'm trying to make a copy of the resizing algorithm of OpenCV with bilinear interpolation in C. What I want to achieve is that the resulting image is exactly the same (pixel value) to that produced by OpenCV. I am particularly interested in shrinking and not in the magnification, and I'm interested to use it on single channel Grayscale images. On the net I read that the bilinear interpolation algorithm is different between shrinkings and enlargements, but I did not find formulas for shrinking-implementations, so it is likely that the code I wrote is totally wrong. What I wrote comes from my knowledge of interpolation acquired in a university course in Computer Graphics and OpenGL. The result of the algorithm that I wrote are images visually identical to those produced by OpenCV but whose pixel values are not perfectly identical (in particular near edges). Can you show me the shrinking algorithm with bilinear interpolation and a possible implementation?
Note: The code attached is as a one-dimensional filter which must be applied first horizontally and then vertically (i.e. with transposed matrix).
Mat rescale(Mat src, float ratio){
float width = src.cols * ratio; //resized width
int i_width = cvRound(width);
float step = (float)src.cols / (float)i_width; //size of new pixels mapped over old image
float center = step / 2; //V1 - center position of new pixel
//float center = step / src.cols; //V2 - other possible center position of new pixel
//float center = 0.099f; //V3 - Lena 512x512 lower difference possible to OpenCV
Mat dst(src.rows, i_width, CV_8UC1);
//cycle through all rows
for(int j = 0; j < src.rows; j++){
//in each row compute new pixels
for(int i = 0; i < i_width; i++){
float pos = (i*step) + center; //position of (the center of) new pixel in old map coordinates
int pred = floor(pos); //predecessor pixel in the original image
int succ = ceil(pos); //successor pixel in the original image
float d_pred = pos - pred; //pred and succ distances from the center of new pixel
float d_succ = succ - pos;
int val_pred = src.at<uchar>(j, pred); //pred and succ values
int val_succ = src.at<uchar>(j, succ);
float val = (val_pred * d_succ) + (val_succ * d_pred); //inverting d_succ and d_pred, supposing "d_succ = 1 - d_pred"...
int i_val = cvRound(val);
if(i_val == 0) //if pos is a perfect int "x.0000", pred and succ are the same pixel
i_val = val_pred;
dst.at<uchar>(j, i) = i_val;
}
}
return dst;
}

Bilinear interpolation is not separable in the sense that you can resize vertically and the resize again vertically. See example here.
You can see OpenCV's resize code here.

Related

how can i extract v-disparity map from a disparity map

i'm new to opencv and i'm trying to run some codes..i need to get a v-disparity map from a disparity map.i 'm using a two rectified image to get stereo matching and after that the dense disparity map.i got the disparity map and when i tryed to tronsform it on v-disparity i got nothing an empty window appeared.i'm refering to the algorithm proposed by :
Raphael Labayrade, Didier Aubert, Jean-Philippe Tarel in their article Real Time Obstacle Detection in Stereovision on
Non Flat Road Geometry Through ”V-disparity”
Representation.
hear is my code :
int main(int argc, char *argv[]){
int nbrepetion ;
Mat img = imread(argv[1],0);
Mat image(img.rows,img.cols, CV_8UC1);
if(img.empty()){
printf("Could not load image file\n");
exit(0);
}
int height = img.rows;
int width = img.cols;
int a = width ;
int k = 0 ;
uchar pos =0 ;
for(int i = 0; i < height; i++){
for(int j = 0; j < width; j++)
for (int k = 0; k < a; k++){
if(img.at<uchar>(i,j) == img.at<uchar>(i,k)) {
nbrepetion ++ ;
}
}
if(nbrepetion == 1){
image.at<uchar>(i,k) = img.at<uchar>(i,k);
} else {
pos = img.at<uchar>(i,k);
image.at<uchar>(pos,k) = nbrepetion;
}
nbrepetion = 0 ;
}
namedWindow("disparityimage", CV_WINDOW_AUTOSIZE);
imshow("disparityimage", image );
waitKey(0);
return 0;
}
For a v-disparity image:
Use a matrix of size (rows, maxVal) and increment the corresponding element by 1 for each line of the disparity image where the disparity value corresponds to a column in the v-disparity image.
Repeat this along rows for the u-disparity image.
Let us denote disparity image as disp of size (height, width).
The output is v-disparity image of size (height, maxDisp), where maxDisp is maximum value in disparity image. Lets denote it vdisp.
Algorithm (pseudo code) is as follows:
For each i in disp.Rows DO
For each j in disp.Columns
if disp(i, j) > 0 Then
vdisp(i, disp(i,j)++
end
end
end
If you look at your v-disparity image, straight vertical lines represent surfaces of obstacles, and straight diagonal line represent ground surface plane. You can use Hough Transform to identify straight lines in the v-disparity image.
In the paper "FPGA implementation of the V-disparity based obstacles detection approach" it is very good explained.

What is the structure of Point2f in openCV?

I am confused about what does Point2f returns. I have vector<Point2f> corner; So, what would be the coordinate of rows and columns? Will it be following:
int row_coordinate = corner[i].x;
int col_coordinate = corner[i].y;
But I get a segmentation fault if I take the above-mentioned convention. And if I do it like
int row_coordinate = corner[i].y;
int col_coordinate = corner[i].x;
then I get the results but then it seems to be opposite to the OpenCV documentation. Kindly tell me which one is correct. Would be very nice if you provide some documentation link (which I have already tried to search a lot).
If I'm correct, I assume you're confused with the coordinate system of OpenCV.
Since I always use x as width and y as height, in my program, I use OpenCV like this:
// make an image with height 100 and width 200
cv::Mat img = cv::Mat::zeros(100, 200, CV_8UC1);
int width = img.cols;
int height = img.rows;
cv::Point2f pt(10, 20);
// How do I get a pixel at x = 10 and y = 20 ?
int px = img.at<uchar>(pt.y, pt.x); // yep, it's inverted
What does it mean? OpenCV corrdinate system is based on rows and then columns. If you want to get pixels at (x, y) access it using (y, x)

standard deviation of a UIImage/CGImage

I need to calculate the standard deviation on an image I have inside a UIImage object.
I know already how to access all pixels of an image, one at a time, so somehow I can do it.
I'm wondering if there is somewhere in the framework a function to perform this in a better and more efficient way... I can't find it so maybe it doensn't exist.
Do anyone know how to do this?
bye
To further expand on my comment above. I would definitely look into using the Accelerate framework, especially depending on the size of your image. If you image is a few hundred pixels by a few hundred. You will have a ton of data to process and Accelerate along with vDSP will make all of that math a lot faster since it processes everything on the GPU. I will look into this a little more, and possibly put some code in a few minutes.
UPDATE
I will post some code to do standard deviation in a single dimension using vDSP, but this could definitely be extended to 2-D
float *imageR = [0.1,0.2,0.3,0.4,...]; // vector of values
int numValues = 100; // number of values in imageR
float mean = 0; // place holder for mean
vDSP_meanv(imageR,1,&mean,numValues); // find the mean of the vector
mean = -1*mean // Invert mean so when we add it is actually subtraction
float *subMeanVec = (float*)calloc(numValues,sizeof(float)); // placeholder vector
vDSP_vsadd(imageR,1,&mean,subMeanVec,1,numValues) // subtract mean from vector
free(imageR); // free memory
float *squared = (float*)calloc(numValues,sizeof(float)); // placeholder for squared vector
vDSP_vsq(subMeanVec,1,squared,1,numValues); // Square vector element by element
free(subMeanVec); // free some memory
float sum = 0; // place holder for sum
vDSP_sve(squared,1,&sum,numValues); sum entire vector
free(squared); // free squared vector
float stdDev = sqrt(sum/numValues); // calculated std deviation
Please explain your query so that can come up with specific reply.
If I am getting you right then you want to calculate standard deviation of RGB of pixel or HSV of color, you can frame your own method of standard deviation for circular quantities in case of HSV and RGB.
We can do this by wrapping the values.
For example: Average of [358, 2] degrees is (358+2)/2=180 degrees.
But this is not correct because its average or mean should be 0 degrees.
So we wrap 358 into -2.
Now the answer is 0.
So you have to apply wrapping and then you can calculate standard deviation from above link.
UPDATE:
Convert RGB to HSV
// r,g,b values are from 0 to 1 // h = [0,360], s = [0,1], v = [0,1]
// if s == 0, then h = -1 (undefined)
void RGBtoHSV( float r, float g, float b, float *h, float *s, float *v )
{
float min, max, delta;
min = MIN( r, MIN(g, b ));
max = MAX( r, MAX(g, b ));
*v = max;
delta = max - min;
if( max != 0 )
*s = delta / max;
else {
// r = g = b = 0
*s = 0;
*h = -1;
return;
}
if( r == max )
*h = ( g - b ) / delta;
else if( g == max )
*h=2+(b-r)/delta;
else
*h=4+(r-g)/delta;
*h *= 60;
if( *h < 0 )
*h += 360;
}
and then calculate standard deviation for hue value by this:
double calcStddev(ArrayList<Double> angles){
double sin = 0;
double cos = 0;
for(int i = 0; i < angles.size(); i++){
sin += Math.sin(angles.get(i) * (Math.PI/180.0));
cos += Math.cos(angles.get(i) * (Math.PI/180.0));
}
sin /= angles.size();
cos /= angles.size();
double stddev = Math.sqrt(-Math.log(sin*sin+cos*cos));
return stddev;
}

RotatedRect ROI in OpenCV

I have a RotatedRect, I want to do some image processing in the rotated region (say extract the color histogram). How can I get the ROI? I mean get the region(pixels) so that I can do processing.
I find this, but it changes the region by using getRotationMatrix2D and warpAffine, so it doesn't work for my situation (I need to process the original image pixels).
Then I find this suggests using mask, which sounds reasonable, but can anyone teach me how to get the mask as the green RotatedRect below.
Excepts the mask, is there any other solutions ?
Thanks for any hint
Here is my solution, using mask:
The idea is construct a Mat mask by assigning 255 to my RotatedRect ROI.
How to know which point is in ROI (which should be assign to 255)?
I use the following function isInROI to address the problem.
/** decide whether point p is in the ROI.
*** The ROI is a rotated rectange whose 4 corners are stored in roi[]
**/
bool isInROI(Point p, Point2f roi[])
{
double pro[4];
for(int i=0; i<4; ++i)
{
pro[i] = computeProduct(p, roi[i], roi[(i+1)%4]);
}
if(pro[0]*pro[2]<0 && pro[1]*pro[3]<0)
{
return true;
}
return false;
}
/** function pro = kx-y+j, take two points a and b,
*** compute the line argument k and j, then return the pro value
*** so that can be used to determine whether the point p is on the left or right
*** of the line ab
**/
double computeProduct(Point p, Point2f a, Point2f b)
{
double k = (a.y-b.y) / (a.x-b.x);
double j = a.y - k*a.x;
return k*p.x - p.y + j;
}
How to construct the mask?
Using the following code.
Mat mask = Mat(image.size(), CV_8U, Scalar(0));
for(int i=0; i<image.rows; ++i)
{
for(int j=0; j<image.cols; ++j)
{
Point p = Point(j,i); // pay attention to the cordination
if(isInROI(p,vertices))
{
mask.at<uchar>(i,j) = 255;
}
}
}
Done,
vancexu
I found the following post very useful to do the same.
http://answers.opencv.org/question/497/extract-a-rotatedrect-area/
The only caveats are that (a) the "angle" here is assumed to be a rotation about the center of the entire image (not the bounding box) and (b) in the last line below (I think) "rect.center" needs to be transformed to the rotated image (by applying the rotation-matrix).
// rect is the RotatedRect
RotatedRect rect;
// matrices we'll use
Mat M, rotated, cropped;
// get angle and size from the bounding box
float angle = rect.angle;
Size rect_size = rect.size;
// thanks to http://felix.abecassis.me/2011/10/opencv-rotation-deskewing/
if (rect.angle < -45.) {
angle += 90.0;
swap(rect_size.width, rect_size.height);
}
// get the rotation matrix
M = getRotationMatrix2D(rect.center, angle, 1.0);
// perform the affine transformation
warpAffine(src, rotated, M, src.size(), INTER_CUBIC);
// crop the resulting image
getRectSubPix(rotated, rect_size, rect.center, cropped);
If you need a superfast solution, I suggest:
crop a Rect enclosing your RotatedRect rr.
rotate+translate back the cropped image so that the RotatedRect is now equivalent to a Rect. (using warpAffine on the product of the rotation and the translation 3x3 matrices)
Keep that roi of the rotated-back image (roi=Rect(Point(0,0), rr.size())).
It is a bit time-consuming to write though as you need to calculate the combined affine transform.
If you don't care about the speed and want to create a fast prototype for any shape of the region, you can use an openCV function pointPolygonTest() that returns a positive value if the point inside:
double pointPolygonTest(InputArray contour, Point2f pt, bool measureDist)
Simple code:
vector<Point2f> contour(4);
contour[0] = Point2f(-10, -10);
contour[1] = Point2f(-10, 10);
contour[2] = Point2f(10, 10);
contour[3] = Point2f(10, -10);
Point2f pt = Point2f(11, 11);
an double res = pointPolygonTest(contour, pt, false);
if (res>0)
cout<<"inside"<<endl;
else
cout<<"outside"<<endl;

How to get a rectangle around the target object using the features extracted by SIFT in OpenCV

I'm doing project in OpenCV on object detection which consists of matching the object in template image with the reference image. Using SIFT algorithm the features get acurately detected and matched but I want a rectagle around the matched features
My algorithm uses the KD-Tree est ean First technique to get the matches
If you want a rectangle around the detected object, here you have code example with exactly that. You just need to draw a rectangle around the homography H.
Hope it helps. Good luck.
I use the following code, adapted from the SURF algoritm in OpenCV (modules/features2d/src/surf.cpp) to extract a surrounding of a keypoint.
Apart from other examples based on rectangles and ROI, this code returns the patch correctly oriented according to the orientation and scale determined by the feature detection algorithm (both available in the KeyPoint struct).
An example of the results of the detection on several different images:
const int PATCH_SZ = 20;
Mat extractKeyPoint(const Mat& image, KeyPoint kp)
{
int x = (int)kp.pt.x;
int y = (int)kp.pt.y;
float size = kp.size;
float angle = kp.angle;
int win_size = (int)((PATCH_SZ+1)*size*1.2f/9.0);
Mat win(win_size, win_size, CV_8UC3);
float descriptor_dir = angle * (CV_PI/180);
float sin_dir = sin(descriptor_dir);
float cos_dir = cos(descriptor_dir);
float win_offset = -(float)(win_size-1)/2;
float start_x = x + win_offset*cos_dir + win_offset*sin_dir;
float start_y = y - win_offset*sin_dir + win_offset*cos_dir;
uchar* WIN = win.data;
uchar* IMG = image.data;
for( int i = 0; i < win_size; i++, start_x += sin_dir, start_y += cos_dir )
{
float pixel_x = start_x;
float pixel_y = start_y;
for( int j = 0; j < win_size; j++, pixel_x += cos_dir, pixel_y -= sin_dir )
{
int x = std::min(std::max(cvRound(pixel_x), 0), image.cols-1);
int y = std::min(std::max(cvRound(pixel_y), 0), image.rows-1);
for (int c=0; c<3; c++) {
WIN[i*win_size*3 + j*3 + c] = IMG[y*image.step1() + x*3 + c];
}
}
}
return win;
}
I am not sure if the scale is entirely OK, but it is taken from the SURF source and the results look relevant to me.

Resources