How can I get Opencv cv::Mat hsv pixels value? - c++

I have a frame which is taken from video:
VideoCapture cap(videoPath);
Mat frame;
cap >> frame;
Frame have target which is blue. So I use Hsv:
Mat blue_hsv;
cvtColor(frame, blue_hsv, cv::COLOR_RGB2HSV);
inRange(blue_hsv, cv::Scalar(0, 50, 50), cv::Scalar(30, 255, 255), blue_hsv);
HSV İmage
Next, I want to get value of pixels. Is pixel white or black. But it didn't work:
for (int i = 0; i<blue_hsv.rows; i++)
{
for (int j = 0; j<blue_hsv.cols; j++)
{
Vec3b& hsv = blue_hsv.at<Vec3b>(i, j);
cout << hsv[0] << ",";
cout << hsv[1] << ",";
cout << hsv[2] << endl;
}
}
I take the "abord()" error. My main purpose is bringing the figure straight with using Pixels. So what can I do for it? How can reach value of hsv pixels?

Related

Extraction of each HSV value from an image using OpenCV and C++

I used the code below to extract each HSV value from any image and to print each value on the screen.
Mat image_HSV;
cvtColor(ori_image, image_HSV, CV_BGR2HSV);
Mat mask;
inRange(image_HSV, Scalar(100, 0, 0), Scalar(100, 255, 255), mask);
image_HSV.setTo(Scalar(0, 0, 0), mask);
int h = 0;
int s = 0;
int v = 0;
int col = image_HSV.cols;
int row = image_HSV.rows;
int corow = col * row; // image's full pixel number
for (int i = 0; i < image_HSV.cols; i++) { // image row pixel
for (int j = 0; j < image_HSV.rows; j++) { // image col pixel
Vec3b hsv = image_HSV.at<Vec3b>(i,j);
h += hsv.val[0];
s += hsv.val[1];
v += hsv.val[2];
if (hsv[0] != 100) {
hsv[0] = 0;
hsv[1] = 0;
hsv[2] = 0;
}
}
}
cout << "H: " << h / corow << "% \n";
cout << "S: " << s / corow << "% \n";
cout << "V: " << v / corow << "% \n";
waitKey(0);
return 0;
I used all red color image for this time, which RGB values were 255, 0, 0.
However, I have some strange results from this code.
As I know, each H,S,V value range is covered by 0-360, 0-100, and 0-100, respectively.
Further, I also followed the post linked below but I still have a trouble to get right values.
OpenCV (C++) - Set HSV values of a pixel
But, I still don't know how to fix it.
Any help would be greatly appreciated! Thanks!

Filtering For Only Red Contours Pixel By Pixel With an HSV Range

I'm trying to calculate the Mean & Std Deviation for red only contours. I suspect that HSV pixels for red Hue values of a Vec3b are stored from 0-10 and 165-179.
Here is my code:
#include <opencv2\opencv.hpp>
#include <iostream>
#include <vector>
#include <cmath>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
// Mat Declarations
// Mat img = imread("white.jpg");
// Mat src = imread("Rainbro.png");
Mat src = imread("multi.jpg");
// Mat src = imread("DarkRed.png");
Mat Hist;
Mat HSV;
Mat Edges;
Mat Grey;
vector<vector<Vec3b>> hueMEAN;
vector<vector<Point>> contours;
// Variables
int edgeThreshold = 1;
int const max_lowThreshold = 100;
int ratio = 3;
int kernel_size = 3;
int lowThreshold = 0;
// Windows
namedWindow("img", WINDOW_NORMAL);
namedWindow("HSV", WINDOW_AUTOSIZE);
namedWindow("Edges", WINDOW_AUTOSIZE);
namedWindow("contours", WINDOW_AUTOSIZE);
// Color Transforms
cvtColor(src, HSV, CV_BGR2HSV);
cvtColor(src, Grey, CV_BGR2GRAY);
// Perform Hist Equalization to help equalize Red hues so they stand out for
// better Edge Detection
equalizeHist(Grey, Grey);
// Image Transforms
blur(Grey, Edges, Size(3, 3));
Canny(Edges, Edges, max_lowThreshold, lowThreshold * ratio, kernel_size);
findContours(Edges, contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
//Rainbro MAT
//Mat drawing = Mat::zeros(432, 700, CV_8UC1);
//Multi MAT
Mat drawing = Mat::zeros(630, 1200, CV_8UC1);
//Red variation Mat
//Mat drawing = Mat::zeros(600, 900, CV_8UC1);
vector <vector<Point>> ContourPoints;
/* This code for loops through all contours and assigns the value of the y coordinate as a parameter
for the row pointer in the HSV mat. The value vec3b pointer pointing to the pixel in the mat is accessed
and stored for any Hue value that is between 0-10 and 165-179 as Red only contours.*/
for (int i = 0; i < contours.size(); i++) {
vector<Vec3b> vf;
vector<Point> points;
bool isContourRed = false;
for (int j = 0; j < contours[i].size(); j++) {
//Row Y-Coordinate of Mat from Y-Coordinate of Contour
int MatRow = int(contours[i][j].y);
//Row X-Coordinate of Mat from X-Coordinate of Contour
int MatCol = int(contours[i][j].x);
Vec3b *HsvRow = HSV.ptr <Vec3b>(MatRow);
int h = int(HsvRow[int(MatCol)][0]);
int s = int(HsvRow[int(MatCol)][1]);
int v = int(HsvRow[int(MatCol)][2]);
cout << "Coordinate: ";
cout << contours[i][j].x;
cout << ",";
cout << contours[i][j].y << endl;
cout << "Hue: " << h << endl;
// Get contours that are only in the red spectrum Hue 0-10, 165-179
if ((h <= 10 || h >= 165 && h <= 180) && ((s > 0) && (v > 0))) {
cout << "Coordinate: ";
cout << contours[i][j].x;
cout << ",";
cout << contours[i][j].y << endl;
cout << "Hue: " << h << endl;
vf.push_back(Vec3b(h, s, v));
points.push_back(contours[i][j]);
isContourRed = true;
}
}
if (isContourRed == true) {
hueMEAN.push_back(vf);
ContourPoints.push_back(points);
}
}
drawContours(drawing, ContourPoints, -1, Scalar(255, 255, 255), 2, 8);
// Calculate Mean and STD for each Contour
cout << "contour Means & STD of Vec3b:" << endl;
for (int i = 0; i < hueMEAN.size(); i++) {
Scalar meanTemp = mean(hueMEAN.at(i));
Scalar sdTemp;
cout << i << ": " << endl;
cout << meanTemp << endl;
cout << " " << endl;
meanStdDev(hueMEAN.at(i), meanTemp, sdTemp);
cout << sdTemp << endl;
cout << " " << endl;
}
cout << "Actual Contours: " << contours.size() << endl;
cout << "# Contours: " << hueMEAN.size() << endl;
imshow("img", src);
imshow("HSV", HSV);
imshow("Edges", Edges);
imshow("contours", drawing);
waitKey(0);
return 0;
}
I've come across an issue in this particular case:
On the right is the original Image, The left displays the HSV mat, the Edge detection and an arrow is pointing to a contours Mat that I drew after the filtering.
Here is the source image:
After the filtering is complete I just calculate the Mean and STD.
I have a feeling that my range is incorrect for 0-10 and 165-179. Any suggestions or further improvements would help a lot.
Thanks.
A quick test shows me that the range is correct. Without all the contour extraction stuff, if I just filter the colors using 0-10 and 165-179 ranges, I get the two red boxes in the lower-middle range of your input image.
The contour artifact that you see might actually be coming from both a JPEG artifact (if you zoom in at the limit between the white and red box, you can see that it is gradual and not sharp, due to JPEG compression), and the fact that you are only thresholding in the Hue channel. At low saturation, many grey-ish colors which you don't want will actually be fitting within your hue threshold. The solution for that is to filter pixel values in the S and V channel as well.
In your code, that means changing the line if ((h <= 10 || h >= 165 && h <= 180) && ((s > 0) && (v > 0))) { to if ((h <= 10 || h >= 165 && h <= 180) && ((s > 50) && (v > 50))) {
The value 50 is working on that specific sample image, but of course the correct value will depend on your input image.

Wrong mass center point (opencv and moment function)

I'm trying to calculate the mass center of images using OpenCV and I got errors, as you can see in the images (the mass center must not be to closest of any side in this cases). Also, I got mass centers that depends of the rotation and that's incorrect.
Next, you can see the code, input image and output image.
I tried with different example codes, and the results are the same.
Output image: Mass center calculated by the program
Input image: Image Input
Example code:
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
Mat src; Mat srcGray;
RNG rng(12345);
int main(int argc, char **argv)
{
// Load source image and convert it to gray
src = imread(argv[1], 1);
// Convert image to gray and blur it
cvtColor(src, srcGray, CV_BGR2GRAY);
blur(srcGray, srcGray, Size(3, 3));
Mat srcThresh;
double otsu;
otsu = threshold(srcGray, srcThresh, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
Mat cannyOut;
Canny(srcGray, cannyOut, otsu, otsu * 1 / 2, 3, 1);
// Find contours
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(cannyOut, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));
// Get the moments
vector<Moments> mu(contours.size());
for (int i = 0; i < contours.size(); i++)
{
mu[i] = moments(contours[i], false);
}
// Get the mass centers:
vector<Point2f> mc(contours.size());
for (int i = 0; i < contours.size(); i++)
{
mc[i] = Point2f(mu[i].m10 / mu[i].m00, mu[i].m01 / mu[i].m00);
}
// Draw contours
Mat drawing = Mat::zeros(cannyOut.size(), CV_8UC3);
string sObjectNumber; // string which will contain the result
ostringstream sContourNumber; // stream used for the conversion
for (int i = 0; i< contours.size(); i++)
{
// drawing.setTo(Scalar(0.0,0.0,0.0));
sContourNumber << i;
sObjectNumber = sContourNumber.str(); // Convert int to string
Point pCoordinates(mc[i].x + 3, mc[i].y - 3); // Text's coordinates (A little bit off from mass center)
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
drawContours(drawing, contours, i, color, 2, 8, hierarchy, 0, Point());
circle(drawing, mc[i], 4, color, -1, 8, 0); // Draw mass center
putText(drawing, sObjectNumber, pCoordinates, CV_FONT_HERSHEY_COMPLEX, 1, color, 2, 8); // Write object number
sContourNumber.str(""); // Clear string
sContourNumber.clear(); // Clear any error flags
// imshow("Contours", drawing);
// waitKey();
}
double hu[7];
for (int i = 0; i < contours.size(); i++)
{
cout << "Contour: " << i << " Area: " << contourArea(contours[i]) << " Length: " << arcLength(contours[i], true) << "\n";
for (int j = 0; j < 7; j++)
{
HuMoments(mu[i], hu);
cout << "Contour: " << i << " Hu: " << j << " Result: " << hu[j] << "\n";
}
cout << "\n";
}
imshow("Contours", drawing);
waitKey(0);
return(0);
}
Very thanks for all!
Diego

opencv graphcut doesn't return correct mask

I have this code:
int main(int argc, char* argv[])
{
Mat image0=imread("C:\\Working Dir\\Tests\\TestBlending\\shop0.jpg");
Mat image1=imread("C:\\Working Dir\\Tests\\TestBlending\\shop1.jpg");
image0.convertTo(image0,CV_32FC3,1/255.0);
image1.convertTo(image1,CV_32FC3,1/255.0);
// our corners are just at (0,0)
cv::Point corner1;
corner1.x = 0;
corner1.y = 0;
cv::Point corner2;
corner2.x = 0;
corner2.y = 0;
std::vector<cv::Point> corners;
corners.push_back(corner1);
corners.push_back(corner2);
std::vector<cv::Mat> masks;
Mat mask0(image0.size(), CV_8U);
mask0(Rect(0, 0, mask0.cols, mask0.rows)).setTo(255);
Mat mask1(image1.size(), CV_8U);
mask1(Rect(0, 0, mask1.cols, mask1.rows)).setTo(255);
masks.push_back(mask0);
masks.push_back(mask1);
std::vector<cv::Mat> sources;
sources.push_back(image0);
sources.push_back(image1);
cv::detail::GraphCutSeamFinder seam_finder;
seam_finder.find(sources, corners, masks);
printf("%lu\n", masks.size());
for(int i = 0; i < masks.size(); i++)
{
std::cout << "MASK = "<< std::endl << " " << masks.at(i) << std::endl << std::endl;
}
return 0;
}
and the images that I am using are:
The masks that I am getting is all 255 for image 0 and all zero for image 1.
What is the problem and how can I fix it?
Edit1
I noted that input images should be in tif format so the application can see the transparent pixels in each image so here is the images files in tif format:
I used smartblend (http://wiki.panotools.org/SmartBlend) to blend these two images and I can get this image:

Access pixels with Mat OpenCV

I would like to access pixels in RGB with OpenCV 2.3.
I'm trying like this but it's like every pixels are equal frame after frame because I got no output. Images are from my webcam and I can see them.
Btw RED = 0;
THX
Mat frame;
Mat oldFrame;
VideoCapture cap(0);
cap >> oldFrame;
sumFramePix = oldFrame.cols * oldFrame.rows;
nbChannels = oldFrame.channels();
cout << "NbcHANNELs : " << nbChannels << endl;
imshow("Video 1", oldFrame);
while(1)
{
cap >> frame;
imshow("Video 1", frame);
for(int i=0; i<frame.rows; i++)
{
for(int j=0; j<frame.cols; j++)
{
if (frame.ptr<uchar>(i)[nbChannels*j+RED] < oldFrame.ptr<uchar>(i)[nbChannels*j+RED])
{
cout << "==============-";
}
}
}
oldFrame = frame;
if(waitKey(300) >= 0) break;
}
Change
oldFrame = frame;
to
oldFrame = frame.clone();
You are creating two Mat objects that point to the same data. clone() makes a deep copy.