I'm using OpenNI and OpenCV (but without the latest code with openni support). If I just send the depth channel to the screen - it will look dark and difficult to understand something. So I want to show a depth channel for the user in a color but cannot find how to do that without losing of accuracy. Now I do it like that:
xn::DepthMetaData xDepthMap;
depthGen.GetMetaData(xDepthMap);
XnDepthPixel* depthData = const_cast<XnDepthPixel*>(xDepthMap.Data());
cv::Mat depth(frame_height, frame_width, CV_16U, reinterpret_cast<void*>(depthData));
cv::Mat depthMat8UC1;
depth.convertTo(depthMat8UC1, CV_8UC1);
cv::Mat falseColorsMap;
cv::applyColorMap(depthMat8UC1, falseColorsMap, cv::COLORMAP_AUTUMN);
depthWriter << falseColorsMap;
But in this case I get worse (loosing details) output than, for instance, kinects software for windows shows me. So I'm looking for a function in OpenNI or OpenCV with a better transformation.
ghttps://github.com/OpenNI/OpenNI2/blob/master/Samples/Common/OniSampleUtilities.h
the link is the code for histogram equalization. In short, it makes the probability of each level equal and optimizes mapping between 10,000 levels and 255 levels. That is why Kinect yellowish map looks better than naive I=255*z/z_range.
NOTE: don’t use color for visualization since a human eye is more sensitive to luminance change than to color variation. So with 255 levels of luminance you will get better contrast than with 255*255*255 levels of color. If you still decide to go along the color mapping avenue use HSV color space where you can manipulate Hue 0..360 deg, Value 1..0 and better set saturation to max. Map depth to hue and value, convert to RGB and display. Than go back to histogram equalization ;)
Try this:
const float scaleFactor = 0.05f;
depth.convertTo(depthMat8UC1, CV_8UC1, scaleFactor);
imshow("depth gray",depthMat8UC1);
Play with the value to get a result you're happy with
Related
Does the second channel of a C2 image represent the alpha channel or do they just fill the gap between C1-C3,C4?
You are mistaking colorspaces with channels. For example you have a greyscale colorspace, which is represented with 1 channel. Then you have BGR with 3 channels, and BGRA with 4. Here the 4th channel is the Alpha value. OpenCV supports several types of colorspaces.
OpenCV is opened to your needs, in some cases you have a mat with 2 values per pixel, for example Dense Optical Flow results, which have a vector of movement of each pixel (x,y vector). You may even create a greyscale image with alpha value for whatever reason or algorithm you have... in this case it will be a CV_8UC2. However this is not a standard colorspace in OpenCV, and a lot of the algorithms have hard constraints on the color space so they may not work with this Mat type.
A cv::Mat can have more than 4 channels even (up to 512 the last time I checked, for more info check the constant CV_CN_MAX), but beware that this may not work with all of OpenCV functions and it will more like a container to your custom algorithms.
I'll be using OpenCV's cascade training functions.
But before that I need to prepare training data.
I just want to know if OpenCV can support it if my positive samples have transparency? Like for example if I want the classifier to learn how a vehicle looks, then can I supply positive sample images that have vehicles standing on a transparent background?
As mentioned in the comments above, the haar features are only computed on the grayscale image. This might pose a problem as you mentioned, when the default color of 0 might cause the "wheels" to lose contrast. You can probably "standardize" the transparent color rather than have it default to 0.
The first thing is you can load in all 4 channels (including your alpha channel) and then use the alpha channel to set the transparent part to a certain value.
Python version
I = cv2.imread("image.jpg", cv2.CV_LOAD_IMAGE_UNCHANGED)
alpha = I[:, :, 3]
G = cv2.cvtColor(I, cv2.COLOR_BGRA2GRAY)
G[alpha == 0] = 125 # Set transparent region to 125. Change to suit your needs.
C++
vector<cv::Mat> channels;
cv::split(I, channels);
cv::Mat alpha = channels[3];
alpha = 255 - alpha; // Invert mask so we select the transparent regions.
cv::Mat G = cv::cvtColor(I, cv::COLOR_BGRA2GRAY);
G.setTo(cv::Scalar(125), alpha);
As a note of caution, I think you might have to be careful about some of the operations above, e.g., loading image with alpha and "alpha = 255 - alpha;". I believe they are only available only in later versions of OpenCV. I'm using OpenCV 2.4.7 and it works (for the python version. I haven't tried the C++ but it should be the same). So if things don't work, check whether these operations are supported for your version of OpenCV. If not there are ways to get round them.
I have a image which is multi colored.
I want to calculate the dominant color of the image. the dominant color is red, i want to filter the red out. i am doing the following code in opencv but its not performing.
inRange(input_image, Scalar(0, 0, 0), Scalar(0, 0, 255), output);
How can i get the dominant color otherwise? My final project should determine the maximum color of the object on its own. What is the best method for this?
You should quantize (reduce number of colors) your image before searching the for the most frequent color.
Why? Imagine image that has 100 pixels of (0,0,255) (blue color int RGB), 100 pixels of (0,0,254) (almost blue - you even won't find the difference) and 150 pixels of (0,255,0) (green). What is the most frequent color here? Obviously, it's green. But after quantization you will got 200 pixels of blue and 150 pixels of green.
Read this discussion: How to reduce the number of colors in an image with OpenCV?. Here's simple example:
int coef = 200;
Mat quantized = img/coef;
quantized = quantized*coef;
And this is what I've got after applying it:
Also you can use k-means or mean-shift to do that (this is much efficient way).
The best method is by analyzing histograms.
Your problem is a classical "find the peak and area under the peak". By having an image file (let's say we take only the third channel for simplicity):
You will have to find the highest peak in that histogram. The easiest method is to simply query the X for which Y is maximized. More advanced methods work with windows - they average the Y-values of 10 consecutive data points, etc.
Also, work in the HSV or YCrCb color space. HSV is good because the "Hue" channel translates very closely to what you mean by "Color". RGB is really not well suited for image analysis.
I have been trying to obtain the image brightness in Opencv, and so far I have used calcHist and considered the average of the histogram values. However, I feel this is not accurate, as it does not actually determine the brightness of an image. I performed calcHist over a gray scale version of the image, and tried to differentiate between the avergae values obtained from bright images over that of moderate ones. I have not been successful so far. Could you please help me with a method or algorithm, that can be realised through OpenCv, to estimate brightness of an image? Thanks in advance.
I suppose, that HSV color model will be usefull in your problem, where channel V is Value:
"Value is the brightness of the color and varies with color saturation. It ranges from 0 to 100%. When the value is ’0′ the color space will be totally black. With the increase in the value, the color space brightness up and shows various colors."
So use OpenCV method cvCvtColor(const CvArr* src, CvArr* dst, int code), that converts an image from one color space to another. In your case code = CV_BGR2HSV.Than calculate histogram of third channel V.
I was about to ask the same, but then found out, that similar question gave no satisfactory answers. All answers I've found on SO deal with human observation of a single pixel RGB vs HSV.
From my observations, the subjective brightness of an image also depends strongly on the pattern. A star in a dark sky may look more bright than a cloudy sky by day, while the average pixel value of the first image will be much smaller.
The images I use are grey-scale cell-images produced by a microscope. The forms vary considerably. Sometimes they are small bright dots on very black background, sometimes less bright bigger areas on not so dark background.
My approach is:
Find histogram maximum (HMax) using threshold for removing hot pixels.
Calculate mean values of all pixel between HMax * 2/3 and HMax
The ratio 2/3 could be also increased to 3/4 (which reduces the range of pixels considered as bright).
The approach works quite well, as different cell-patterns with same titration produce similar brightness.
P.S.: What I actually wanted to ask is, whether there is a similar function for such a calculation in OpenCV or SimpleCV. Many thanks for any comments!
I prefer Valentin's answer, but for 'yet another' way of determining average-per-pixel brightness, you can use numpy and a geometric mean instead of arithmetic. To me it has better results.
from numpy.linalg import norm
def brightness(img):
if len(img.shape) == 3:
# Colored RGB or BGR (*Do Not* use HSV images with this function)
# create brightness with euclidean norm
return np.average(norm(img, axis=2)) / np.sqrt(3)
else:
# Grayscale
return np.average(img)
A bit of OpenCV C++ source code for a trivial check to differentiate between light and dark images. This is inspired by the answer above provided years ago by #ann-orlova:
const int darkness_threshold = 128; // you need to determine what threshold to use
cv::Mat mat = get_image_from_device();
cv::Mat hsv;
cv::cvtColor(mat, hsv, CV_BGR2HSV);
const auto result = cv::mean(hsv);
// cv::mean() will return 3 numbers, one for each channel:
// 0=hue
// 1=saturation
// 2=value (brightness)
if (result[2] < darkness_threshold)
{
process_dark_image(mat);
}
else
{
process_light_image(mat);
}
I'm trying to create an histogram using opencv. I have an image (32 bit) that came out from a blurring operation, so I just know that the values are in the range [-0.5; 0.5] but I don't know anything else about the starting data.
the problem is that I don't understand how to set the parameters to compute such histogram.
the code I wrote is:
int numbins=1000;
float range[]={-0.5, 0.5};
float *ranges[]={range};
CvHistogram *hist=cvCreateHist(1, &numbins, CV_HIST_ARRAY, ranges, 1);
cvCalcHist(&img, hist);
were img is the image I want to get the histogram. if I try to print the histogram I just get a black picture, while with the same function I get a correct histogram if use a grayscale 8bit image.
Have you looked at the calcHist example? Also, the camshiftdemo makes heavy use of histograms.
Are you normalizing the histogram output with normalize before display (camshiftdemo shows how to do this)? Values near 0 will appear black when displayed, but when normalized between say 0 and 255 will show up nicely.