Very basic question coming from a newbie in OpenCV. I just want to create an image with every pixel set to 0 (black). I have used the following code in the main() function:
IplImage* imgScribble = cvCreateImage(cvSize(320, 240), 8, 3);
And what I get is a solid gray image, instead of the black one.
Thanks in advance !
What version of opencv you are using?
For Mat,
#include <opencv2/opencv.hpp>
cv::Mat image(320, 240, CV_8UC3, cv::Scalar(0, 0, 0));
I can suggest two more altrnatives:
IplImage* imgScribble = cvCreateImage(cvSize(320, 240), 8, 3);
// Here you can set any color
cvSet(imgScribble, cvScalar(0,0,0));
// Here only black
cvZero(imgScribble);
The call to
cvCreateImage(cvSize(320, 240), 8, 3);
Create the image in the memory, but I don't think it initialize the data.
You should try this to initialize :
step= imgScribble->widthStep;
data = (uchar *)imgScribble->imageData;
for(i=0;i<imgScribble->height;i++) for(j=0;j<img->width;j++) for(k=0;k<3;k++)
data[i*step+j*3+k]=0;
(Inspired from this (Example C Program))
For Python:
import numpy as np
X_DIMENSION = 288
Y_DIMENSION = 382
black_image = np.zeros((X_DIMENSION, Y_DIMENSION))
With this code you generate a numpy array which is what is expected for opencv images and fill it with zero which is the color for black. This code is made for grayscale images. If you want it to be an RGB black image, just add 3 at the end of the tupple to create the dimensions np.zeros((X_DIMENSION, Y_DIMENSION, 3))
black and white image mean single channel image. you can simply created it as follows.
Mat img(500, 1000, CV_8UC1, Scalar(a));
"a" in between 0-255
you can see more examlpe and details from following page
https://progtpoint.blogspot.com/2017/01/tutorial-3-create-image.html
Here is my contribution:
cv::Mat output = cv::Mat::zeros(cv::Size(320, 240), CV_8UC3);
#include "stdafx.h"
#include <opencv/cxcore.h>
#include <opencv/highgui.h>
#include <iostream>
using namespace cv;
using namespace std;
#define LOAD_OPTION CV_LOAD_IMAGE_COLOR
int main( int argc, char** argv )
{
IplImage *image;
image = cvLoadImage("picture.jpg",0); // 0 : BLACK AND WHITE , Without 0 -> Color Picture
cvNamedWindow("Image",CV_WINDOW_AUTOSIZE);
cvShowImage("Image", image);
waitKey(-1);
return 0;
}
Related
Say I have a floating point image, e.g. in 32FC1 format for a thermal image, and I want to display it using (preferably) ROS or openCV tools, while also being able to see the current pixel value (e.g. temperature) my mouse is hovering over. How would I do that? Rviz can display the image, but will not show any pixel values. Image_view is also able to display the image, but will show the pixel value in RGB.
Thank you!
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using std::cout;
using std::endl;
// create a global Mat
cv::Mat img_32FC1;
// function to be called on mouse event
// displays values on console, it can be modified to print values on image
void mouseEventCallBack (int event, int x, int y, int flags, void *userdata)
{
if(event == cv::EVENT_MOUSEMOVE)
{
cout<<"x = "<<x<<", y = "<<y<<" value = "<<img_32FC1.at<float>(y,x)<<endl;
}
}
int main()
{
// original color image, CV_8UC3
cv::Mat img_8UC3 = cv::imread("image.jpg",cv::IMREAD_UNCHANGED), img_8UC1;
// convert original image to gray, CV_8UC1
cv::cvtColor(img_8UC3, img_8UC1, cv::COLOR_BGR2GRAY);
// convert to float, CV_32FC1
img_8UC1.convertTo(img_32FC1, CV_32FC1);
img_32FC1 /= 255.0;
// create a window
cv::namedWindow("window",CV_WINDOW_AUTOSIZE);
// set MouseCallback function
cv::setMouseCallback("window", mouseEventCallBack);
// Display image
cv::imshow("window", img_8UC1);
cv::waitKey(0);
cv::destroyAllWindows();
return 0;
}
I have an image with very low intensity contrast from its background.
The first line between the two arrows is the line with low contrast.
The second line is ok. Please see in the below image.
The original image is as shown below.
I used the following method to enhance the contrast in Gray scale.
First the image is changed to Gray color and used the following method.
cv::Mat temp;
for (int i = 0; i < 1; i++) // number of iterations has to be adjusted
{
cv::threshold(image, temp, 0, 255, CV_THRESH_BINARY| CV_THRESH_OTSU);//
cv::bitwise_and(image, temp, image);
cv::normalize(image, image, 0, 255, cv::NORM_MINMAX, -1, temp);
}
I have image with a little bit higher in contrast in Gray scale, but is there any method better than this in Gray scale or Color?
I would look at histogram equalization, that might serve your needs. Basic (global) equalization or even adaptive can yield great results. Parameters will likely need to be tuned for the adaptive method (using the one from the docs example for now).
I get (global equalization - left; adaptive equalization - right):
Once the equalization is done, you might have better luck with thresholding (though your example is very low contrast):
From there, you can use standard contour/shape matching etc to try to find the location of your 1st black line.
Gotten from
import cv2
import matplotlib.pyplot as plt
import numpy as np
raw_img_load = cv2.imread('H1o8X.png')
imgr = cv2.cvtColor(raw_img_load,cv2.COLOR_BGR2GRAY)
clahe = cv2.createCLAHE(clipLimit=30.0, tileGridSize=(8,8))
imgray_ad = clahe.apply(imgr)#adaptive
imgray = cv2.equalizeHist(imgr)#global
res = np.hstack((imgray,imgray_ad))#so we can plot together
plt.imshow(res,cmap='gray')
plt.show()
ret,thresh = cv2.threshold(imgray_ad,150,255,type=cv2.THRESH_BINARY+cv2.THRESH_OTSU)
plt.imshow(thresh,cmap='gray')
plt.show()
EDIT: based on #Doleron's answer, for this particular problem I would recommend using fastNlMeansDenoising (applied before any histogram equalization). Note, however, that it can be a slow function for high-res images/time-sensitive image processing.
The #Antoine Zambelli answer is awsome and it is the correct one. Anyway, I dug some here and and tried to remove the noise previously with fastNlMeansDenoising to improve the final result:
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "opencv2/photo.hpp"
using namespace cv;
using cv::CLAHE;
int main(int argc, char** argv) {
Mat srcImage = imread("H1o8X.png", CV_LOAD_IMAGE_GRAYSCALE);
imshow("src", srcImage);
Mat denoised;
fastNlMeansDenoising(srcImage, denoised, 10);
Mat image = denoised;
Ptr<CLAHE> clahe = createCLAHE();
clahe->setClipLimit(30.0);
clahe->setTilesGridSize(Size(8, 8));
Mat imgray_ad;
clahe->apply(image, imgray_ad);
Mat imgray;
cv::equalizeHist(image, imgray);
imshow("imgray_ad", imgray_ad);
imshow("imgray", imgray);
Mat thresh;
threshold(imgray_ad, thresh, 150, 255, THRESH_BINARY | THRESH_OTSU);
imshow("thresh", thresh);
Mat result;
Mat kernel = Mat::ones(8, 8, CV_8UC1);
erode(thresh, result, kernel);
imshow("result", result);
waitKey();
return 0;
}
Here is my code (working after taking inputs from zindarod)
#include <stdio.h>
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/nonfree/nonfree.hpp"
using namespace cv;
static void help()
{
printf("\nThis program demonstrates using features2d detector, descriptor extractor and simple matcher\n"
"Using the sift desriptor:\n"
"\n"
"Usage:\n matcher_simple <image1> <image2>\n");
}
int main(int argc, char** argv)
{
if(argc != 3)
{
help();
return -1;
}
Mat img1 = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
Mat img2 = imread(argv[2], CV_LOAD_IMAGE_GRAYSCALE);
Rect regionone(151, 115, 42, 27);
Rect regiontwo(141, 105, 52, 37);
Mat dst,mask;
Rect rect(151, 115, 42, 27);
mask = Mat::zeros(img1.size(),CV_8UC1);
mask(Rect(151,115,42,27)) = 1;
img1.copyTo(dst,mask);
if(img1.empty() || img2.empty())
{
printf("Can't read one of the images\n");
return -1;
}
// detecting keypoints
SiftFeatureDetector detector(400);
vector<KeyPoint> keypoints1, keypoints2;
detector.detect(dst, keypoints1);
detector.detect(img2, keypoints2);
// computing descriptors
SiftDescriptorExtractor extractor;
Mat descriptors1, descriptors2;
extractor.compute(dst, keypoints1, descriptors1);
extractor.compute(img2, keypoints2, descriptors2);
// matching descriptors
BFMatcher matcher(NORM_L2);
vector<DMatch> matches;
matcher.match(descriptors1, descriptors2, matches);
// drawing the results
namedWindow("matches", 1);
Mat img_matches;
drawMatches(dst, keypoints1, img2, keypoints2, matches, img_matches);
imshow("masked image",dst);
//imshow("matches", img_matches);
waitKey(0);
return 0;
}
My aim is to compare two different parts of two different images .
You can run above code after using
g++ above_code.cpp -o bincode -I /usr/include/ `pkg-config --libs --cflags opencv`
./bincode image1.png image2.png
It seems that I am passing a rectangular region to keypoint detector as a result , the keypoints1 are saved with coordinates relative to 151,115 .
So , I should pass a masked image to keypoint detector .
How can I create a matrix filled with zeroes (or 255) but with rectangular region at 151,115 copied from img1 ?
thanks.
The following copies source image to destination image based on mask.
Mat src = imread("source.jpg",-1),dst,mask;
Rect rect(151, 115, 42, 27);
mask = Mat::zeros(src.Size(),CV_8UC1);
rectangle(mask, Point(rect.x,rect.y),Point(rect.x+rect.width,rect.y+rect.height),Scalar(255),-1);
src.copyTo(dst,mask);
Although there's a better way for your problem, you can translate your keypoints to the size of the original image.
I need to find the percentage of skintone of a person in a given image.
I have been able to count all the pixels with skin colour so far but I am having trouble ignoring the background of the person so I can count the number of pixels for the percentage.
BackgroundSubtractorMOG2 bg;
bg.nmixtures =3;
bg.bShadowDetection=false;
bg.operator ()(img,fore);
bg.getBackgroundImage(back);
img is my image. I was trying to separate the back and fore mat objects, but with the above code snippet back and fore take the same value as the img. Nothing is happening.
Can you point me in the right direction as to what changes I have to make to get it right?
I was able to run some similar code found here:
http://mateuszstankiewicz.eu/?p=189
I had to change a couple of things, but it ended up working properly (back and fore are not the same as img when displayed:
int main(int argc, char *argv[]) {
Mat frame, back, fore;
VideoCapture cap(0);
BackgroundSubtractorMOG2 bg;
vector<std::vector<Point> > contours;
namedWindow("Frame");
namedWindow("Background");
namedWindow("Foreground");
for(;;) {
cap >> frame;
bg.operator ()(frame, fore);
bg.getBackgroundImage(back);
erode(fore, fore, Mat());
dilate(fore, fore, Mat());
findContours(fore, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
drawContours(frame, contours, -1, Scalar(0, 0, 255), 2);
imshow("Frame", frame);
imshow("Background", back);
imshow("Foreground", fore);
if(waitKey(1) == 27) break;
}
return 0;
}
I know OpenCV only supports binary masks.
But I need to do an overlay where I have a grayscale mask that specifies transparency of the overlay.
Eg. if a pixel in the mask is 50% white it should mean a cv::addWeighted operation for that pixel with alpha=beta=0.5, gamma = 0.0.
Now, if there is no opencv library function, what algorithm would you suggest as the most efficient?
I did something like this for a fix.
typedef double Mask_value_t;
typedef Mat_<Mask_value_t> Mask;
void cv::addMasked(const Mat& src1, const Mat& src2, const Mask& mask, Mat& dst)
{
MatConstIterator_<Vec3b> it1 = src1.begin<Vec3b>(), it1_end = src1.end<Vec3b>();
MatConstIterator_<Vec3b> it2 = src2.begin<Vec3b>();
MatConstIterator_<Mask_value_t> mask_it = mask.begin();
MatIterator_<Vec3b> dst_it = dst.begin<Vec3b>();
for(; it1 != it1_end; ++it1, ++it2, ++mask_it, ++dst_it)
*dst_it = (*it1) * (1.0-*mask_it) + (*it2) * (*mask_it);
}
I have not optimized nor made safe this code yet with assertions.
Working assumptions: all Mat's and the Mask are the same size and Mat's are normal three channel color images.
I have a similar problem, where I wanted to apply a png with transparency.
My solution was using Mat expressions:
void AlphaBlend(const Mat& imgFore, Mat& imgDst, const Mat& alpha)
{
vector<Mat> vAlpha;
Mat imgAlpha3;
for(int i = 0; i < 3; i++) vAlpha.push_back(alpha);
merge(vAlpha,imgAlpha3)
Mat blend = imgFore.mul(imgAlpha3,1.0/255) +
imgDst.mul(Scalar::all(255)-imgAlpha3,1.0/255);
blend.copyTo(imgDst);
}
OpenCV supports RGBA images which you can create by using mixchannels or the split and merge functions to combine your images with your greyscale mask. I hope this is what you are looking for!
Using this method you can combine your grayscale mask with your image like so:
cv::Mat gray_image, mask, rgba_image;
std::vector<cv::Mat> result;
cv::Mat image = cv::imread(image_path);
cv::split(image, result);
cv::cvtColor(image, gray_image, CV_BGR2GRAY);
cv::threshold(gray_image, mask, 128, 255, CV_THRESH_BINARY);
result.push_back(mask);
cv::merge(result, rgba_image);
imwrite("rgba.png", rgba_image);
Keep in mind that you cannot view RGBA images using cv::imshow as described in read-rgba-image-opencv and you cannot save your image as jpeg since that format does not support transparency. It seems that you can combine channels using cv::cvtcolor as shown in opencv-2-3-convert-mat-to-rgba-pixel-array