I am doing a simple reading and displaying PNG image. I am reading a png image with background as transparent. I am converting the image in greyscale and then displaying it. But the converted image is looking something like this:
Original Image:
Greyscale image:
Here is the code. What am I doing wrong?:
Mat image = imread("3X3_a11.png",IMREAD_GRAYSCALE);
Mat output(image.size(),image.type());
// connectedComponents(image, output);
imshow("Output", image);
waitKey(0);
destroyAllWindows();
Your RGBA image is malformed, or at least is very wierd. On loading I see the warning:
libpng warning: iCCP: known incorrect sRGB profile
You can however get the binary version need for cv::connectedComponents with simple processing like:
#include <opencv2\opencv.hpp>
int main()
{
cv::Mat4b img4b = cv::imread("path_to_image", cv::IMREAD_UNCHANGED);
// Convert to grayscale getting rid of alpha channel
cv::Mat1b img(img4b.rows, img4b.cols, uchar(0));
for (int r = 0; r < img4b.rows; ++r) {
for (int c = 0; c < img4b.cols; ++c) {
if (img4b(r, c) == cv::Vec4b(255,255,255,255)) {
img(r, c) = uchar(255);
}
if (img4b(r, c)[3] == 0) {
img(r, c) = uchar(255);
}
}
}
cv::imshow("img", img);
cv::waitKey();
}
Result:
Related
Good Day! I'm using imwrite command to save the image below after cropping them in OpenCV (C++) but it seems like it included the black portion surrounding it in writing. All I want is to save the cropped one. Please help.
Here's my code
Mat mask,draft,res;
int nPixels;
char c=0;
while(true && c!='q') {
imshow("SAMPLE", img);
if(!roi.isSet())
roi.set("SAMPLE");
if (roi.isSet()) {
roi.createMask(img.size());
mask = roi.getMask();
res = mask & img.clone();
imwrite("masked.png",res);
imshow("draft", res);
}
c = waitKey(1);
}
Here is an example how to crop an image and save the croped image (see comment from api55). Maybe that helps you.
cv::Mat img = cv::imread("Path/To/Image/image.png", cv::IMREAD_GRAYSCALE);
if(image.empty())
return -1;
cv::Rect roi(0, 0, 100, 100); // define roi here as x0, y0, width, height
cv::Mat cropedImg(img, roi);
cv::imwrite("Path/To/Save/Location/cropedImage.png", cropedImg);
I am using openCV on C++. In my program I am accessing all the images in a directory using glob function of openCV. And then I am reading and showing the images using imread and imshow functions of openCV.
My image sequence is :
[Black frame - White frame] ---- x50
However the sequence I am getting displayed on screen has some repetition of black frame. I looks like openCV is not reading the files as they are stored in the directory.
Do someone know why this is happening? Did someone encountered similar problem with openCV before?
Here is my code:
void ImageDisp()
{
vector<String> filenames;
String folder = "C:\\Users\\aamir\\Documents\\PythonScripts\\BWSeq_test\\";
glob(folder, filenames);
namedWindow("MyWindow", CV_WINDOW_NORMAL);
cvSetWindowProperty("MyWindow", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);
for (size_t i = 0; i < filenames.size() - 1; i++)
{
printf("----------Changing Image--------\n ");
int k = 0;
` Mat img = imread(filenames[i], CV_LOAD_IMAGE_UNCHANGED);
while (k < 100)
{
imshow("MyWindow", img);
waitKey(1);
ShowCursor(false);
k = k + 1;
}
}
destroyWindow("MyWindow");
return 0;
}
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.
I want to implement a OCR feature.
I have collected some samples and i want to use K-Nearest to implement it.
So, i use the below code to load data and initialize KNearest
KNearest knn = new KNearest;
Mat mData, mClass;
for (int i = 0; i <= 9; ++i)
{
Mat mImage = imread( FILENAME ); // the filename format is '%d.bmp', presenting a 15x15 image
Mat mFloat;
if (mImage.empty()) break; // if the file doesn't exist
mImage.convertTo(mFloat, CV_32FC1);
mData.push_back(mFloat.reshape(1, 1));
mClass.push_back( '0' + i );
}
knn->train(mData, mClass);
Then, i call the code to find best result
for (vector<Mat>::iterator it = charset.begin(); it != charset.end(); ++it)
{
Mat mFloat;
it->convertTo(mFloat, CV_32FC1); // 'it' presents a 15x15 gray image
float result = knn->find_nearest(mFloat.reshape(1, 1), knn->get_max_k());
}
But, my application crashes at find_nearest.
Anyone could help me?
I seemed to find the problem...
My sample image is a converted gray image by cvtColor, but my input image isn't.
After i add
cvtColor(mImage, mImage, COLOR_BGR2GRAY);
between
if (mImage.empty()) break;
mImage.convertTo(mFloat, CV_32FC1);
find_nearest() return a value and my application is fine.
I'm trying to split two images along a seam, and then blend them together. In this process, I need to cut out each image along the seam by applying a mask. How can I apply a mask? I tried bitwise_and and multiplying the mask and the image, but neither worked.
int pano_width = left_template_width + right_template_width - roi_width;
// add zeros to the right of the left template
Mat full_left = Mat::zeros(roi_height, pano_width, CV_32FC3);
Mat tmp_l = full_left(Rect(0,0, left_template_width, roi_height));
imshow("Scene mask", mask0f3);
imshow("Cropped scene", cropped_scene);
Mat left_masked;
//bitwise_and(cropped_scene, mask0f3, left_masked); // full_left looks all black
multiply(cropped_scene, mask0f3, left_masked); // full_left looks like the scene mask, but with an extra black rectangle on the right side
left_masked.copyTo(tmp_l);
imshow("Full left", full_left);
I resorted to a terribly efficient, but working, hack:
void apply_mask(Mat& img, Mat mask) {
CV_Assert(img.rows == mask.rows);
CV_Assert(img.cols == mask.cols);
print_mat_type(img);
print_mat_type(mask);
for (int r = 0; r < mask.rows; r++) {
for (int c = 0; c < mask.cols; c++) {
if (mask.at<uchar>(r, c) == 0) {
img.at<Vec3f>(r, c) = Vec3f(0, 0, 0);
}
}
}
}
Here you have snippet that works using bitwise_and (look at docs how this methods works)
Mat img = imread("lena.jpg");
Mat mask = Mat::zeros(img.rows, img.cols, CV_8UC1);
Mat halfMask = mask(cv::Rect(0,0,img.rows/2, img.cols/2));
halfMask.setTo(cv::Scalar(255));
Mat left_masked;
bitwise_and(img, cv::Scalar(255,255,255), left_masked, mask);
So you can use something like:
bitwise_and(cropped_scene, cv::Scalar(255,255,255), left_masked, mask); // mask must be CV_8UC1!
But you have to change type, or create new mask, which has a type of CV_8UC1.
EDIT: Your function apply_mask can look like:
void apply_mask(Mat& img, Mat &mask, Mat &result) {
CV_Assert(img.rows == mask.rows);
CV_Assert(img.cols == mask.cols);
CV_Assert(img.type() == CV_32FC3);
bitwise_and(img, cv::Scalar(1.0f,1.0f,1.0f), result, mask);
}
Unfortunately if you pass input image as an output image in bitwise_and, you've got all black output. But passing another argument works fine.