Copy rows to matrix crashes OpenCV - Visual Studio 2010 C++ - c++

I am trying to copy certain rows from src image to new image called gaps. The gaps image will contain only few rows. However the program crashes at the line with copyTo. The Mat src image is correct, it contains my image because I can view it by imshow().
Mat gaps;
int gap = 6;
for (int r = 0; r < src.rows; r++)
{
if ( r % gap == 0 )
src.row(r).copyTo(gaps.row(r));
}
imshow("gaps", gaps);
waitKey(0);
I am using OpenCV, Visual Studio 2010 C++ on Windows XP.
I tried to add this:
gaps.create(CV_8UC3, 2056,2056); to specify depth and dimensions but it still crashes.

Try this:
// if you want your background to be black --> Scalar(0,0,0)
Mat gaps = Mat(src.size(), src.type(), Scalar(0,0,0));
This is what you'll get, I don't know if that is what you expect/want.
Code
// set your input image
Mat src = imread("{path to input image}");
// your code with the change I proposed
Mat gaps = Mat(src.size(), src.type(), Scalar(0,0,0));
int gap = 6;
for (int r = 0; r < src.rows; r++) {
if ( r % gap == 0 )
src.row(r).copyTo(gaps.row(r));
}
imshow("gaps", gaps);
// create the result image
Mat result = Mat(Size(src.cols * 2, src.rows), src.type(), Scalar(0,0,0));
src.copyTo(result(Rect(0,0,src.cols,src.rows)));
gaps.copyTo(result(Rect(src.cols,0,src.cols,src.rows)));
imshow("result", result);
waitKey();

Related

Matrix assignement value error in opencv C++ with mat.at<uchar>(i,j)

I am learning image processing with OpenCV in C++. To implement a basic down-sampling algorithm I need to work on the pixel level -to remove rows and columns. However, when I assign values with mat.at<>(i,j) other values are assign - things like 1e-38.
Here is the code :
Mat src, dst;
src = imread("diw3.jpg", CV_32F);//src is a 479x359 grayscale image
//dst will contain src low-pass-filtered I checked by displaying it works fine
Mat kernel;
kernel = Mat::ones(3, 3, CV_32F) / (float)(9);
filter2D(src, dst, -1, kernel, Point(-1, -1), 0, BORDER_DEFAULT);
// Now I try to remove half the rows/columns result is stored in downsampled
Mat downsampled = Mat::zeros(240, 180, CV_32F);
for (int i =0; i<downsampled.rows; i ++){
for (int j=0; j<downsampled.cols; j ++){
downsampled.at<uchar>(i,j) = dst.at<uchar>(2*i,2*j);
}
}
Since I read here OpenCV outputing odd pixel values that for cout I needed to cast, I wrote downsampled.at<uchar>(i,j) = (int) before dst.at<uchar> but it does not work also.
The second argument to cv::imread is cv::ImreadModes, so the line:
src = imread("diw3.jpg", CV_32F);
is not correct; it should probably be:
cv::Mat src_8u = imread("diw3.jpg", cv::IMREAD_GRAYSCALE);
src_8u.convertTo(src, CV_32FC1);
which will read the image as 8-bit grayscale image, and will convert it to floating point values.
The loop should look something like this:
Mat downsampled = Mat::zeros(240, 180, CV_32FC1);
for (int i = 0; i < downsampled.rows; i++) {
for (int j = 0; j < downsampled.cols; j++) {
downsampled.at<float>(i,j) = dst.at<float>(2*i,2*j);
}
}
note that the argument to cv::Mat::zeros is CV_32FC1 (1 channel, with 32-bit floating values), so Mat::at<float> method should be used.

OpenCV: output image is blue

so i'm making this project where i'm making the reflection of an image on OpenCV (without using the flip function), and the only problem (i think) to finish it, is that the image that is suppose to come out reflected, is coming out as all blue.
The code i have (i took out the usual part, the problem should be around here):
Mat imageReflectionFinal = Mat::zeros(Size(220,220),CV_8UC3);
for(unsigned int r=0; r<221; r++)
for(unsigned int c=0; c<221; c++) {
Vec3b intensity = image.at<Vec3b>(r,c);
imageReflectionFinal.at<Vec3b>(r,c) = (uchar)(c, -r + (220)/2);
}
///displays images
imshow( "Original Image", image );
imshow("Reflected Image", imageReflectionFinal);
waitKey(0);
return 0;
}
There are some problems with your code. As pointed out, your iteration variables go beyond the actual image dimensions. Do not use hardcoded bounds, you can use inputImage.cols and inputImage.rows instead to obtain the image dimensions.
There’s the variable (a BGR Vec3b) that is set but not used - Vec3b intensity = image.at<Vec3b>(r,c);
Most importantly, it is not clear what you are trying to achieve. The line (uchar)(c, -r + (220)/2); does not give out much info. Also, which direction are you flipping the original image around? X or Y axis?
Here’s a possible solution to flip your image in the X direction:
//get input image:
cv::Mat testMat = cv::imread( "lena.png" );
//Get the input image size:
int matCols = testMat.cols;
int matRows = testMat.rows;
//prepare the output image:
cv::Mat imageReflectionFinal = cv::Mat::zeros( testMat.size(), testMat.type() );
//the image will be flipped around the x axis, so the "target"
//row will start at the last row of the input image:
int targetRow = matRows-1;
//loop thru the original image, getting the current pixel value:
for( int r = 0; r < matRows; r++ ){
for( int c = 0; c < matCols; c++ ) {
//get the source pixel:
cv::Vec3b sourcePixel = testMat.at<cv::Vec3b>( r , c );
//source and target columns are the same:
int targetCol = c;
//set the target pixel
imageReflectionFinal.at<cv::Vec3b>( targetRow , targetCol ) = sourcePixel;
}
//for every iterated source row, decrease the number of
//target rows, as we are flipping the pixels in the x dimension:
targetRow--;
}
Result:

How to pass an image buffer to an OpenCV Mat object?

I am currently programming with a PixeLINK USB3 machine vision camera along with OpenCV in C. I have had some success passing camera images in Mat format with the following code:
PXL_RETURN_CODE rc = PxLInitialize(0, &hCamera);
if (!API_SUCCESS(rc))
{
printf("Error: Unable to initialize a camera. \n");
return EXIT_FAILURE;
}
vector<U8> frameBuffer(3000 * 3000 * 2);
FRAME_DESC frameDesc;
if (API_SUCCESS(PxLSetStreamState(hCamera, START_STREAM)))
{
while (true)
{
frameDesc.uSize = sizeof(frameDesc);
rc = GetNextFrame(hCamera, (U32)frameBuffer.size(), &frameBuffer[0],
&frameDesc, 5);
Mat image(2592, 2048, CV_8UC1);
Mat imageCopy;
// Where passing of image data occurs
int k = 0;
for (int row = 0; row < 2048; row++)
{
for (int col = 0; col < 2592; col++)
{
image.at<uchar>(row, col) = frameBuffer[k];
k++;
}
}...
As I mentioned this works, but it seems very sloppy. I have looked online but haven't found too much detail.
I have tried:
Mat image(2592, 2048, CV_8UC1, &frameBuffer, size_t step=AUTO_STEP);
as well as,
Mat image(2592, 2048, CV_8UC1, frameBuffer, size_t step=AUTO_STEP).
The former is the only one that compile successfully, and displays gibberish - I mean, it doesn't form an image.
Have you tried switching the row and col of your Mat?
You initialized your Mat with row = 2592, col = 2048,
but you're using switched row and col in your for() loop.
I think this code should work properly:
Mat image(2048, 2592, CV_8UC1, &frameBuffer[0]);
Or, if you're using C++11,
Mat image(2048, 2592, CV_8UC1, frameBuffer.data());

Texture Analysis using Local Binary Patterns (faces module)

Problem;
Since I didn't find an implementation of LBP in the OpenCV lib, I added the faces module to my OpenCV build. Which does have a LBP implementation.
I'm trying to do texture analysis using local binary patterns (lbp) to determine what is road and what are lines and what isn't road. So I divided my problem up in 3 'labels'. (Road / Lines / The rest )
After that I took 3 random sample images and made subimages with these labels. In other words I selected the road, lines, all the rest and used this as input for the training.
Training:
for (int i = 0; i < names.size(); i++) {
Mat trainingData = imread(names[i]), output;
if (!trainingData.empty()) {
cvtColor(trainingData, output, CV_RGB2GRAY);
int pos = names[i].find_last_of('_');
cv::String l = names[i].substr(pos + 1, 1);
const char *sub = l.c_str();
int label = atoi(sub);
grayscaleImages.push_back(output);
labels.push_back(label);
}
}
Ptr<LBPHFaceRecognizer> lbp = createLBPHFaceRecognizer(2, 4, 10, 10);
lbp->train(grayscaleImages, labels);
Using LBP to predict:
for (int i = 0; i < dataset.images.size(); i++) {
Mat image = (dataset.images[i]).clone();
Mat original = image.clone();
for (int i = 0 ; i < image.size().width; i += squareSize) {
for (int j = image.size().height / 2 ; j < image.size().height; j += squareSize) {
Mat subImage = image(Range(j, j + squareSize), Range(i, i + squareSize));
subImage = applySobel(subImage);
int predict = lbp->predict(subImage);
}
}
imshow("Image", original);
waitKey(0);
}
My question is why this isn't working? I'm kinda puzzeled about the prediction aswell. It doesn't seem to be anywhere near close to what I want it to do?
Do I have the implement LBP myself? Does the LBP implementation of the faces module do something special?
Do you have any suggestion on other methods for texture analysis specifically for the case of road / no road?
So here is a general overview of the files I'm using.
Input:
Selecting our training data:
Results of selecting: (every file has a _number to specify the label)
Final result after training on a random image of the same set. Purple represents road, green is line (or road marking).

OpenCV-2.4.8.2: imshow differs from imwrite

I'm using OpenCV2.4.8.2 on Mac OS 10.9.5.
I have the following snippet of code:
static void compute_weights(const vector<Mat>& images, vector<Mat>& weights)
{
weights.clear();
for (int i = 0; i < images.size(); i++) {
Mat image = images[i];
Mat mask = Mat::zeros(image.size(), CV_32F);
int x_start = (i == 0) ? 0 : image.cols/2;
int y_start = 0;
int width = image.cols/2;
int height = image.rows;
Mat roi = mask(Rect(x_start,y_start,width,height)); // Set Roi
roi.setTo(1);
weights.push_back(mask);
}
}
static void blend(const vector<Mat>& inputImages, Mat& outputImage)
{
int maxPyrIndex = 6;
vector<Mat> weights;
compute_weights(inputImages, weights);
// Find the fused pyramid:
vector<Mat> fused_pyramid;
for (int i = 0; i < inputImages.size(); i++) {
Mat image = inputImages[i];
// Build Gaussian Pyramid for Weights
vector<Mat> weight_gaussian_pyramid;
buildPyramid(weights[i], weight_gaussian_pyramid, maxPyrIndex);
// Build Laplacian Pyramid for original image
Mat float_image;
inputImages[i].convertTo(float_image, CV_32FC3, 1.0/255.0);
vector<Mat> orig_guassian_pyramid;
vector<Mat> orig_laplacian_pyramid;
buildPyramid(float_image, orig_guassian_pyramid, maxPyrIndex);
for (int j = 0; j < orig_guassian_pyramid.size() - 1; j++) {
Mat sized_up;
pyrUp(orig_guassian_pyramid[j+1], sized_up, Size(orig_guassian_pyramid[j].cols, orig_guassian_pyramid[j].rows));
orig_laplacian_pyramid.push_back(orig_guassian_pyramid[j] - sized_up);
}
// Last Lapalcian layer is the same as the Gaussian layer
orig_laplacian_pyramid.push_back(orig_guassian_pyramid[orig_guassian_pyramid.size()-1]);
// Convolve laplacian original with guassian weights
vector<Mat> convolved;
for (int j = 0; j < maxPyrIndex + 1; j++) {
// Create 3 channels for weight gaussian pyramid as well
vector<Mat> gaussian_3d_vec;
for (int k = 0; k < 3; k++) {
gaussian_3d_vec.push_back(weight_gaussian_pyramid[j]);
}
Mat gaussian_3d;
merge(gaussian_3d_vec, gaussian_3d);
//Mat convolved_result = weight_gaussian_pyramid[j].clone();
Mat convolved_result = gaussian_3d.clone();
multiply(gaussian_3d, orig_laplacian_pyramid[j], convolved_result);
convolved.push_back(convolved_result);
}
if (i == 0) {
fused_pyramid = convolved;
} else {
for (int j = 0; j < maxPyrIndex + 1; j++) {
fused_pyramid[j] += convolved[j];
}
}
}
// Blending
for (int i = (int)fused_pyramid.size()-1; i > 0; i--) {
Mat sized_up;
pyrUp(fused_pyramid[i], sized_up, Size(fused_pyramid[i-1].cols, fused_pyramid[i-1].rows));
fused_pyramid[i-1] += sized_up;
}
Mat final_color_bgr;
fused_pyramid[0].convertTo(final_color_bgr, CV_32F, 255);
final_color_bgr.copyTo(outputImage);
imshow("final", outputImage);
waitKey(0);
imwrite(outputImagePath, outputImage);
}
This code is doing some basic pyramid blending for 2 images. The key issues are related to imshow and imwrite in the last line. They gave me drastically different results. I apologize for displaying such a long/messy code, but I am afraid this difference is coming from some other parts of the code that can subsequently affect the imshow and imwrite.
The first image shows the result from imwrite and the second image shows the result from imshow, based on the code given. I'm quite confused about why this is the case.
I also noticed that when I do these:
Mat float_image;
inputImages[i].convertTo(float_image, CV_32FC3, 1.0/255.0);
imshow("float image", float_image);
imshow("orig image", image);
They show exactly the same thing, that is they both show the same picture in the original rgb image (in image).
IMWRITE functionality
By default, imwrite, converts the input image into Only 8-bit (or 16-bit unsigned (CV_16U) in case of PNG, JPEG 2000, and TIFF) single-channel or 3-channel (with ‘BGR’ channel order) images can be saved using this function.
So whatever format you feed in for imwrite, it blindly converts into CV_8U with a range 0(black) - 255(white) in BGR format.
IMSHOW - problem
So when noticed your function, fused_pyramid[0].convertTo(final_color_bgr, CV_32F, 255); fused_pyramid is already under mat type 21 (floating point CV_32F). You tried to convert into floating point with a scale factor 255. This scaling factor 255 caused the problem # imshow. Instead to visualize, you can directly feed in fused_pyramid without conversion as already it is scaled to floating point between 0.0(black) - 1.0(white).
Hope it helps.