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)
Related
Thank you to the people who previously helped me, I have managed to work a lot on my generative business cards assignment.
I want to randomly resize 9 images in processing but can't seem to find a good example on the internet on how to do it. The size of the images is 850x550 which is also the background size.
Does anyone know a good and easy to follow tutorial? or could give me an example?
The Processing's documentation on the image() method covers this.
I still wrote you some skeleton code to demonstrate:
PImage img;
int w, h;
float scaleModifier = 1;
void setup() {
size(800, 600);
img = loadImage("bean.jpeg");
w = img.width;
h = img.height;
}
void draw() {
background(0);
image(img, 0, 0, w, h); // here is the important line
}
// Every click will resize the image
void mouseClicked() {
scaleModifier += 0.1;
if (scaleModifier > 1) {
scaleModifier = 0.1;
}
w = (int)(img.width * scaleModifier);
h = (int)(img.height * scaleModifier);
}
What's important to know is the following:
image() has 2 signatures:
image(img, a, b)
image(img, a, b, c, d)
Where the following applies:
img => the PImage for your image
a => x coordinate where to draw the image
b => y coordinate where to draw the image
c => the image's width (if it's different from the image's width, this implies a resize)
d => the image's height (also implies a resize if it's different from the "real" height)
Have fun!
say you have stored an image in a PImage object, image
you can generate two random integers for the img_width and img_height of the image and then resize() the image using resize() method
int img_width = foor(random(min_value, max_value));
int img_height = floor(random(min_value, max_value));
image.resize(img_width, img_height); //this simple code resizes the image to any dimension
or if you want to keep the same aspect ratio, then you can use this approach
//first set either of width or height to a random value
int img_width = floor(random(min_value, max_value));
//then proportionally calculate the other dimension of the image
float ratio = (float) image.width/image.height;
int img_height = floor(img_width/ratio);
image.resize(img_width, img_height);
You can check this out YouTube playlist for some tutorials of image processing.
I have the histogram for an image which i have calculated. I want to display this as an image so that I can actually see the histogram. I think my problem is to do with scaling although i am slightly confused over the co ordinate system starting with 0,0 in the top left as well.
int rows = channel.rows;
int cols = channel.cols;
int hist[256] = {0};
for(int i = 0; i<rows; i++)
{
for(int k = 0; k<cols; k++ )
{
int value = channel.at<cv::Vec3b>(i,k)[0];
hist[value] = hist[value] + 1;
}
}
Mat histPlot = cvCreateMat(256, 500,CV_8UC1);
for(int i = 0; i < 256; i++)
{
int mag = hist[i];
line(histPlot,Point(i,0),Point(i,mag),Scalar(255,0,0));
}
namedWindow("Hist",1);
imshow("Hist",histPlot);
This is my calculation for creating my histogram and displaying the result. If i do mag/100 in my second loop then i get some resemblance of a plot appearing (although upside down). I call this method whenever i adjust a value of my image, so the histogram should also change shape, which it doesn't appear to do. Any help in scaling the histogram and displaying it properly is appreciated.
please don't use cvCreateMat ( aka, the old c-api ), you also seem to have rows and cols wrong, additionally, if you want a color drawing, you need a color image as well, so make that:
Mat histPlot( 500, 256, CV_8UC3 );
image origin is top-left(0,0), so you've got to put y in reverse:
line(histPlot,Point(i,histPlot.rows-1),Point(i,histPlot.rows-1-mag/100),Scalar(255,0,0));
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.
I know this might be very rudimentary, but I am new to OpenCV. Could you please tell me how to obtain the size of a matrix in OpenCV?. I googled and I am still searching, but if any of you know the answer, please help me.
Size as in number of rows and columns.
And is there a way to directly obtain the maximum value of a 2D matrix?
cv:Mat mat;
int rows = mat.rows;
int cols = mat.cols;
cv::Size s = mat.size();
rows = s.height;
cols = s.width;
Note that apart from rows and columns there is a number of channels and type. When it is clear what type is, the channels can act as an extra dimension as in CV_8UC3 so you would address a matrix as
uchar a = M.at<Vec3b>(y, x)[i];
So the size in terms of elements of elementary type is M.rows * M.cols * M.cn
To find the max element one can use
Mat src;
double minVal, maxVal;
minMaxLoc(src, &minVal, &maxVal);
For 2D matrix:
mat.rows – Number of rows in a 2D array.
mat.cols – Number of columns in a 2D array.
Or:
C++: Size Mat::size() const
The method returns a matrix size: Size(cols, rows) . When the matrix is more than 2-dimensional, the returned size is (-1, -1).
For multidimensional matrix, you need to use
int thisSizes[3] = {2, 3, 4};
cv::Mat mat3D(3, thisSizes, CV_32FC1);
// mat3D.size tells the size of the matrix
// mat3D.size[0] = 2;
// mat3D.size[1] = 3;
// mat3D.size[2] = 4;
Note, here 2 for z axis, 3 for y axis, 4 for x axis.
By x, y, z, it means the order of the dimensions. x index changes the fastest.
If you are using the Python wrappers, then (assuming your matrix name is mat):
mat.shape gives you an array of the type- [height, width, channels]
mat.size gives you the size of the array
Sample Code:
import cv2
mat = cv2.imread('sample.png')
height, width, channel = mat.shape[:3]
size = mat.size
A complete C++ code example, may be helpful for the beginners
#include <iostream>
#include <string>
#include "opencv/highgui.h"
using namespace std;
using namespace cv;
int main()
{
cv:Mat M(102,201,CV_8UC1);
int rows = M.rows;
int cols = M.cols;
cout<<rows<<" "<<cols<<endl;
cv::Size sz = M.size();
rows = sz.height;
cols = sz.width;
cout<<rows<<" "<<cols<<endl;
cout<<sz<<endl;
return 0;
}
I need to convert an 8-bit IplImage to a 32-bits IplImage. Using documentation from all over the web I've tried the following things:
// general code
img2 = cvCreateImage(cvSize(img->width, img->height), 32, 3);
int height = img->height;
int width = img->width;
int channels = img->nChannels;
int step1 = img->widthStep;
int step2 = img2->widthStep;
int depth1 = img->depth;
int depth2 = img2->depth;
uchar *data1 = (uchar *)img->imageData;
uchar *data2 = (uchar *)img2->imageData;
for(h=0;h<height;h++) for(w=0;w<width;w++) for(c=0;c<channels;c++) {
// attempt code...
}
// attempt one
// result: white image, two red spots which appear in the original image too.
// this is the closest result, what's going wrong?!
// see: http://files.dazjorz.com/cache/conversion.png
((float*)data2+h*step2+w*channels+c)[0] = data1[h*step1+w*channels+c];
// attempt two
// when I change float to unsigned long in both previous examples, I get a black screen.
// attempt three
// result: seemingly random data to the top of the screen.
data2[h*step2+w*channels*3+c] = data1[h*step1+w*channels+c];
data2[h*step2+w*channels*3+c+1] = 0x00;
data2[h*step2+w*channels*3+c+2] = 0x00;
// and then some other things. Nothing did what I wanted. I couldn't get an output
// image which looked the same as the input image.
As you see I don't really know what I'm doing. I'd love to find out, but I'd love it more if I could get this done correctly.
Thanks for any help I get!
The function you are looking for is cvConvertScale(). It automagically does any type conversion for you. You just have to specify that you want to scale by a factor of 1/255 (which maps the range [0...255] to [0...1]).
Example:
IplImage *im8 = cvLoadImage(argv[1]);
IplImage *im32 = cvCreateImage(cvSize(im8->width, im8->height), 32, 3);
cvConvertScale(im8, im32, 1/255.);
Note the dot in 1/255. - to force a double division. Without it you get a scale of 0.
Perhaps this link can help you?
Edit In response to the second edit of the OP and the comment
Have you tried
float value = 0.5
instead of
float value = 0x0000001;
I thought the range for a float color value goes from 0.0 to 1.0, where 1.0 is white.
Floating point colors go from 0.0 to 1.0, and uchars go from 0 to 255. The following code fixes it:
// h is height, w is width, c is current channel (0 to 2)
int b = ((uchar *)(img->imageData + h*img->widthStep))[w*img->nChannels + c];
((float *)(img2->imageData + h*img2->widthStep))[w*img2->nChannels + c] = ((float)b) / 255.0;
Many, many thanks to Stefan Schmidt for helping me fix this!
If you do not put the dot (.), some compilers will understand is as an int division, giving you a int result (zero in this case).
You can create an IplImage wrapper using boost::shared_ptr and template-metaprogramming. I have done that, and I get automatic garbage collection, together with automatic image conversions from one depth to another, or from one-channel to multi-channel images.
I have called the API blImageAPI and it can be found here:
http://www.barbato.us/2010/10/14/image-data-structure-based-shared_ptr-iplimage/
It is very fast, and make code very readable, (good for maintaining algorithms)
It is also can be used instead of IplImage in opencv algorithms without changing anything.
Good luck and have fun writing algorithms!!!
IplImage *img8,*img32;
img8 =cvLoadImage("a.jpg",1);
cvNamedWindow("Convert",1);
img32 = cvCreateImage(cvGetSize(img8),IPL_DEPTH_32F,3);
cvConvertScale(img8,img32,1.0/255.0,0.0);
//For Confirmation Check the pixel values (between 0 - 1)
for(int row = 0; row < img32->height; row++ ){
float* pt = (float*) (img32->imageData + row * img32->widthStep);
for ( int col = 0; col < width; col++ )
printf("\n %3.3f , %3.3f , %3.3f ",pt[3*col],pt[3*col+1],pt[3*col+2]);
}
cvShowImage("Convert",img32);
cvWaitKey(0);
cvReleaseImage(&img8);
cvReleaseImage(&img32);
cvDestroyWindow("Convert");