I would use gamma correction to a image.
So, I have to pow every pixel intensity of my source image with a G = 0.6.
I have problem cause the destination image is completely wrong.
Maybe I have a casting problem when I take pixel from source image.
Here my code:
#include <opencv2/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main() {
Mat src = imread("spine1.jpeg");
Mat dst = Mat(src.rows, src.cols, CV_8UC1);
cvtColor(src, src, CV_8UC1);
dst = Scalar(0);
for (int x = 0; x < src.rows; x++) {
for (int y = 0; y < src.cols; y++) {
int pixelValue = (int)src.at<uchar>(x, y);
dst.at<uchar>(x, y) = pow(pixelValue, 0.6);
}
}
namedWindow("Input", CV_WINDOW_AUTOSIZE);
namedWindow("Output", CV_WINDOW_AUTOSIZE);
imshow("Input", src);
imshow("Output", dst);
waitKey(0);
return 0;
}
Edit: change cvtColor(src, src, CV_8UC1); in cvtColor(src, src, COLOR_BGR2GRAY);
The call to cvtColor is wrong. You should use:
cvtColor(src, src, COLOR_BGR2GRAY);
Also, you can make your code much simpler, and less error prone:
#include <opencv2/opencv.hpp>
int main()
{
// Load the image as grayscale
cv::Mat1b src = cv::imread("path_to_img", cv::IMREAD_GRAYSCALE);
// Convert to double for "pow"
cv::Mat1d dsrc;
src.convertTo(dsrc, CV_64F);
// Compute the "pow"
cv::Mat1d ddst;
cv::pow(dsrc, 0.6, ddst);
// Convert back to uchar
cv::Mat1b dst;
ddst.convertTo(dst, CV_8U);
// Show results
imshow("SRC", src);
imshow("DST", dst);
waitKey();
return 0;
}
Related
I want to use the fitLine function to come up with a line to draw on my source image src_crop. I load the frame in my main() and call the drawLine().
But the code aborts with the following error :
Code:
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace std;
using namespace cv;
/// Global variables
Mat src_gray;
Mat src_crop;
Mat dst, detected_edges;
int edgeThresh = 1;
int lowThreshold = 27;
int const max_lowThreshold = 100;
int ratio = 3;
int kernel_size = 3;
char* window_name = "Edge Map";
int i,j;
void drawLine(int, void*)
{
vector<Vec4f> outline;
vector<Point2f> ssline;
int flag2 = 0;
/// Reduce noise with a kernel 3x3
blur(src_gray, detected_edges, Size(3, 3));
/// Canny detector
Canny(detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size);
/// Using Canny's output as a mask, we display our result
dst.create(detected_edges.size(), detected_edges.type());
dst = Scalar::all(0);
src_crop.copyTo(dst, detected_edges);
//namedWindow("Detected Edges", CV_WINDOW_AUTOSIZE);
//imshow("Detected Edges", detected_edges);
cvtColor(dst, dst, CV_BGR2GRAY);
for (j = 0; j < dst.cols; j++)
{
for (i = 0; i < dst.rows; i++)
{
if (Scalar(dst.at<uchar>(i,j)).val[0] >= 90)
{
//cout << "Hi";
flag2 = 1;
break;
}
}
if (flag2 == 1)
break;
}
int k = j;
int l = i;
for (j = k; j < dst.cols; j++)
{
Point2f ss = Point2f(l,j);
ssline.push_back(ss);
}
fitLine(ssline, outline, CV_DIST_L1, 0, 0.01, 0.01);
//imshow("Result", src_crop);
}
int main(int argc, char** argv)
{
/// Load an image
src = imread(s);
if (!src.data)
{
return -1;
}
/// Create a matrix of the same type and size as src (for dst)
//dst.create(src.size(), src.type());
src_crop = src;
/// Convert the image to grayscale
cvtColor(src_crop, src_gray, CV_BGR2GRAY);
/// Create a window
namedWindow(window_name, CV_WINDOW_AUTOSIZE);
/// Create a Trackbar for user to enter threshold
createTrackbar("Min Threshold:", window_name, &lowThreshold, max_lowThreshold, drawLine);
/// Show the image
drawLine(0, 0);
if (waitKey(30) >= 0) break;
return 0;
}
The code stops working at the point fitLine() is called. This I found by testing the code with printf statements.
Can anyone kindly help me solve the issue?
Aside the fact the your code won't compile, the issue is that you're passing to fitLine the parameter outline as a vector<Vec4f>, while it should be a Vec4f.
Change outline declaration as:
Vec4f outline;
User,
I want to crop that Triangle on the image and show it in another window with opencv c++. I know all three Coordinates.
Can anyone help me? I did not find any answer on the Internet about "triangle cropping". Thanks!
EDIT: The Problem here is that i cannot use ROI for cropping the Triangle. I have to copy just the triangle without any background or something around. Is it possible to create my own ROI by knowing the Coordinates of the triangle [p1(302,179), p2(329,178), p3(315,205)]?
cv::Mat inputImage = cv::imread("input.png");
if (inputImage.channels() > 1)
{
cv::cvtColor(inputImage, inputImage, CV_RGB2GRAY);
}
// replace these values with your actual coordinates
// I found these by first saving your provided image, then
// using Microsoft Paint
int x0 = 242;
int y0 = 164;
int x1 = 314;
int y1 = 38;
int x2 = 387;
int y2 = 164;
// then create a line masking using these three points
cv::Mat lineMask = cv::Mat::zeros(inputImage.size(), inputImage.type());
cv::line(lineMask, cv::Point(x0, y0), cv::Point(x1, y1), cv::Scalar(255, 255, 0), 1, 8, 0);
cv::line(lineMask, cv::Point(x0, y0), cv::Point(x2, y2), cv::Scalar(255, 255, 0), 1, 8, 0);
cv::line(lineMask, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(255, 255, 0), 1, 8, 0);
// perform contour detection on your line mask
cv::vector<cv::vector<cv::Point>> contours;
cv::vector<cv::Vec4i> hierarchy;
cv::findContours(lineMask, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
// calculate the distance to the contour
cv::Mat raw_dist(lineMask.size(), CV_32FC1);
for (int i = 0; i < lineMask.rows; i++)
{
for (int j = 0; j < lineMask.cols; j++)
{
raw_dist.at<float>(i, j) = cv::pointPolygonTest(contours[0], cv::Point2f(j, i), true);
}
}
double minVal; double maxVal;
cv::minMaxLoc(raw_dist, &minVal, &maxVal, 0, 0, cv::Mat());
minVal = std::abs(minVal);
maxVal = std::abs(maxVal);
// depicting the distances graphically
cv::Mat mask = cv::Mat::zeros(inputImage.size(), CV_8UC1);
for (int i = 0; i < mask.rows; i++)
{
for (int j = 0; j < mask.cols; j++)
{
if (raw_dist.at<float>(i, j) < 0)
{
mask.at<uchar>(i, j) = static_cast<uchar>(0);
continue;
}
mask.at<uchar>(i, j) = static_cast<uchar>(255);
}
}
// inverse the input image
cv::Mat invInput;
cv::bitwise_not(inputImage, invInput);
// then get only the region of your triangle
cv::Mat outputImage;
invInput.copyTo(outputImage, mask);
cv::bitwise_not(outputImage, outputImage);
// display for debugging purpose
cv::imshow("inputImage", inputImage);
cv::imshow("lineMask", lineMask);
cv::imshow("mask", mask);
cv::imshow("outputImage", outputImage);
cv::waitKey();
This is your inputImage:
This is your lineMask:
This is your created binary mask:
And this is your final outputImage:
References:
OpenCV draw line
OpenCV findContours
Point Polygon Test
you can do it by using mask as shown with the code below
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main( int, char** argv )
{
Mat src = imread( argv[1] );
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY );
gray = gray < 127;
vector<vector<Point> > contours;
findContours(gray, contours,
RETR_EXTERNAL,
CHAIN_APPROX_SIMPLE);
for( size_t i = 0; i< contours.size(); i++ )
{
Rect rect = boundingRect(contours[i]);
Mat mask = gray(rect);
Mat srcROI = src(rect);
srcROI.setTo(Scalar(0,0,255),mask);
imshow("srcROI",srcROI);
waitKey();
}
imshow( "result", src );
waitKey(0);
return(0);
}
EDIT: according the change on the question i suggest the test code below
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;
using namespace std;
int main( int, char** argv )
{
Mat src = imread("lena.jpg");
vector<Point> points;
points.push_back( Point(200,200));
points.push_back( Point(370,370));
points.push_back( Point(220,410));
Mat mask = Mat::zeros( src.size(), CV_8UC1 );
fillConvexPoly( mask, points, Scalar( 255 ));
Rect rect = boundingRect( points );
Mat roi = src( rect ).clone();
mask = mask( rect ).clone();
rect.x = rect.x - 180;
rect.y = rect.y - 180;
Mat srcROI = src( rect );
roi.copyTo( srcROI, mask );
imshow( "result", src );
waitKey(0);
return(0);
}
As you told that you know co-ordinates of the triangle, using below code you can find triangle.
Mat image = imread("imagePath");
bitwise_not(image, image);
Mat grayImage;
cv::cvtColor(image, grayImage, CV_RGB2GRAY);
cv::vector<cv::vector<cv::Point> > contours;
cv::vector<cv::Vec4i> hierarchy;
cv::findContours(grayImage, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
Mat contourMat(grayImage.size(), grayImage.type(), Scalar(255));
for(int i = 0; i < contours.size(); i++)
{
if(contours[i].data()->x == 314 && contours[i].data()->y == 37)
drawContours(contourMat, contours, i, Scalar(0), CV_FILLED, 8, hierarchy);
}
imshow("WindowName", contourMat);
Hope this will help.
I know that it is possible to equalize the histogram of an image like:
equalizeHist(image, image);
and if I want I can define a roi and equalize just this roi in the image:
Mat aux3 = image.clone();
equalizeHist(image(Rect(0,100, 200,200)), aux3(Rect(0,100, 200,200)));
What I would like to do now (and I don't know if it is possible), is to define a Roi(contour) using a vector of points (cv::vector contour) and equalize this roi (this roi not always will be a rectangle)
So, The question here is:
Is it possible to equalize a portion of the image that is not a rectangle using openCV functions?
There is no builtin function in OpenCV to perform histogram equalization with a mask. Still you can write your custom one.
Get a grayscale image:
// Load image
Mat3b img = imread("path_to_image");
// Convert to grayscale
Mat1b gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
Form a mask from your points:
// Your vector of points
vector<Point> pts = { Point(300, 180), Point(450, 150), Point(600, 200), Point(650, 350), Point(300,300) };
// Create the mask
Mat1b mask(img.rows, img.cols, uchar(0));
vector<vector<Point>> ptsarray{pts};
fillPoly(mask, ptsarray, Scalar(255));
Call your custom function equalizeHistWithMask that equalize the image with a mask:
// Equalize with mask
Mat1b equalized;
equalizeHistWithMask(gray, equalized, mask);
Here the full code for reference, with the equalizeHistWithMask function:
#include <iostream>
#include <vector>
#include <algorithm>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void equalizeHistWithMask(const Mat1b& src, Mat1b& dst, Mat1b mask = Mat1b())
{
int cnz = countNonZero(mask);
if (mask.empty() || ( cnz == src.rows*src.cols))
{
equalizeHist(src, dst);
return;
}
dst = src.clone();
// Histogram
vector<int> hist(256,0);
for (int r = 0; r < src.rows; ++r) {
for (int c = 0; c < src.cols; ++c) {
if (mask(r, c)) {
hist[src(r, c)]++;
}
}
}
// Cumulative histogram
float scale = 255.f / float(cnz);
vector<uchar> lut(256);
int sum = 0;
for (int i = 0; i < hist.size(); ++i) {
sum += hist[i];
lut[i] = saturate_cast<uchar>(sum * scale);
}
// Apply equalization
for (int r = 0; r < src.rows; ++r) {
for (int c = 0; c < src.cols; ++c) {
if (mask(r, c)) {
dst(r, c) = lut[src(r,c)];
}
}
}
}
int main()
{
// Load image
Mat3b img = imread("path_to_image");
// Convert to grayscale
Mat1b gray;
cvtColor(img, gray, COLOR_BGR2GRAY);
// Your vector of points
vector<Point> pts = { Point(300, 180), Point(450, 150), Point(600, 200), Point(650, 350), Point(300,300) };
// Create the mask
Mat1b mask(img.rows, img.cols, uchar(0));
vector<vector<Point>> ptsarray{pts};
fillPoly(mask, ptsarray, Scalar(255));
// Equalize with mask
Mat1b equalized;
equalizeHistWithMask(gray, equalized, mask);
imshow("Gray", gray);
imshow("Mask", mask);
imshow("Equalized", equalized);
waitKey();
return 0;
}
Credits
The code is based on this question on answers.opencv.org
I have Implemented a Canny Edge detector using “Church Canny Edge” image as below. now I want to extend/modify my code in order to colour every pixel with a gradient between 22.5 and 67.5 degrees in the same image.
can you please give me lines of codes need be added to my current implementation?
<< EDITION 1 >>
this is the version after editing it by help of Miki. when I build it , I get a black window which means somehow I am messing the image show part of code. any tips ?
#include <opencv2/opencv.hpp>
#include <vector>
#include <algorithm>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
using namespace std;
using namespace cv;
Mat image, im_gray;
int main( int argc, char** argv )
{
/// Load an image
if(argc > 1)
image = imread(argv[1]);
else
image = imread("Church Canny Edge.png");
/// Create a window
namedWindow( "window");
if(image.empty())
cout << "Output sentence";
// Mat3b img = imread("Church Canny Edge.png");
Mat1b im_gray;
cvtColor(image, im_gray, cv::COLOR_BGR2GRAY);
Mat1b detected_edges;
GaussianBlur(im_gray, detected_edges, Size(3, 3), 0, 0);
int lowThreshold = 200;
int ratio = 3;
int kernel_size = 3;
Canny(detected_edges, detected_edges, lowThreshold,
lowThreshold*ratio, kernel_size);
// Compute Sobel derivatives
Mat1f sx, sy;
Sobel(detected_edges, sx, CV_32F, 1, 0, kernel_size);
Sobel(detected_edges, sy, CV_32F, 0, 1, kernel_size);
// Compute edge angle
Mat1f angles(detected_edges.rows, detected_edges.cols, 0.f);
for (int r = 0; r < detected_edges.rows; ++r)
{
for (int c = 0; c < detected_edges.cols; ++c)
{
angles(r, c) = atan2(sy(r, c), sx(r,c));
}
}
// Convert radians to degrees
angles = (angles / CV_PI * 180.0);
// Get values in range
Mat1b maskPositive;
inRange(angles, Scalar(22.5), Scalar(67.5), maskPositive);
Mat1b maskNegative;
inRange(angles, Scalar(-67.5), Scalar(-22.5), maskNegative);
Mat1b mask = maskNegative | maskPositive;
// Show results
Mat3b result;
cvtColor(detected_edges, result, COLOR_GRAY2BGR);
for (int r = 0; r < detected_edges.rows; ++r)
{
for (int c = 0; c < detected_edges.cols; ++c)
{
if (mask(r, c) && detected_edges(r, c))
{
result(r, c) = Vec3b(0,255,0);
}
}
}
waitKey(0);
return 0;
}
Image:
You can compute the gradient angle using Sobel derivatives:
// Compute Sobel derivatives
Mat1f sx, sy;
Sobel(detected_edges, sx, CV_32F, 1, 0, kernel_size);
Sobel(detected_edges, sy, CV_32F, 0, 1, kernel_size);
// Compute edge angle
Mat1f angles(detected_edges.rows, detected_edges.cols, 0.f);
for (int r = 0; r < detected_edges.rows; ++r)
{
for (int c = 0; c < detected_edges.cols; ++c)
{
angles(r, c) = atan2(sy(r, c), sx(r,c));
}
}
// Convert radians to degrees
angles = (angles / CV_PI * 180.0);
Angles:
Then you can keep only values in a specified range:
// Get values in range
Mat1b maskPositive;
inRange(angles, Scalar(22.5), Scalar(67.5), maskPositive);
Mat1b maskNegative;
inRange(angles, Scalar(-67.5), Scalar(-22.5), maskNegative);
Mat1b mask = maskNegative | maskPositive;
You can then color pixels that are both in mask and in canny edges:
// Show results
Mat3b result;
cvtColor(detected_edges, result, COLOR_GRAY2BGR);
for (int r = 0; r < detected_edges.rows; ++r)
{
for (int c = 0; c < detected_edges.cols; ++c)
{
if (mask(r, c) && detected_edges(r, c))
{
result(r, c) = Vec3b(0,255,0); // green
}
}
}
Result:
NOTES
You probably don't want to draw pixels with a given gradient, but extract lines and draw lines with a given slope. You can do this using Hough Transform (available in OpenCV). I won't show this since it's not what was asked here.
You can basically copy this code into your CannyThreshold function
Full code for reference:
#include <opencv2/opencv.hpp>
#include <vector>
#include <algorithm>
using namespace std;
using namespace cv;
int main()
{
Mat3b img = imread("path_to_image");
Mat1b im_gray;
cvtColor(img, im_gray, COLOR_BGR2GRAY);
Mat1b detected_edges;
GaussianBlur(im_gray, detected_edges, Size(3, 3), 0, 0);
int lowThreshold = 200;
int ratio = 3;
int kernel_size = 3;
Canny(detected_edges, detected_edges, lowThreshold,
lowThreshold*ratio, kernel_size);
// Compute Sobel derivatives
Mat1f sx, sy;
Sobel(detected_edges, sx, CV_32F, 1, 0, kernel_size);
Sobel(detected_edges, sy, CV_32F, 0, 1, kernel_size);
// Compute edge angle
Mat1f angles(detected_edges.rows, detected_edges.cols, 0.f);
for (int r = 0; r < detected_edges.rows; ++r)
{
for (int c = 0; c < detected_edges.cols; ++c)
{
angles(r, c) = atan2(sy(r, c), sx(r,c));
}
}
// Convert radians to degrees
angles = (angles / CV_PI * 180.0);
// Get values in range
Mat1b maskPositive;
inRange(angles, Scalar(22.5), Scalar(67.5), maskPositive);
Mat1b maskNegative;
inRange(angles, Scalar(-67.5), Scalar(-22.5), maskNegative);
Mat1b mask = maskNegative | maskPositive;
// Show results
Mat3b result;
cvtColor(detected_edges, result, COLOR_GRAY2BGR);
for (int r = 0; r < detected_edges.rows; ++r)
{
for (int c = 0; c < detected_edges.cols; ++c)
{
if (mask(r, c) && detected_edges(r, c))
{
result(r, c) = Vec3b(0,255,0);
}
}
}
return 0;
}
I try to count the number of hearts in the following image by using a canny edge detection algorithm and contours.
But after the contours I have gotten image like this and it has contoured 4 instead of 3. What kind of method I have to follow to count any number of object different shapes of deck card pack. I only need number of symbols in the middle.
Here is my c++ code
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/core/core.hpp>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
using namespace cv;
using namespace std;
Mat src;
Mat dst;
Mat canny_output;
//this is function for loading the image
void loadImage(char* source){
Mat tmp;
/// Load source image and convert it to gray
src = imread( source, 1 );
/// Convert image to gray and blur it
cvtColor( src, tmp, CV_RGB2GRAY );
//blur( src_gray, src_gray, Size(3,3) );
bitwise_not( tmp, src);
}
void clearImage(){
int i,j;
int r = 10;
Mat clone;
src.copyTo(clone);
for(i = 0;i < src.rows;++i){
j = 0;
clone.at<Vec3b>(i,j) = Vec3b(0,0,0);
for(j = 0;j < src.cols;++j){
if(src.at<cv::Vec3b>(i,j) == cv::Vec3b(255,255,255)){
rectangle(
clone,
cv::Point(i-r, j),
cv::Point(i+r, j+r),
cv::Scalar(255, 255, 255)
);
}
}
}
}
void detectImages(){
int thresh = 100;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
Canny( src, canny_output, thresh, thresh*2, 3 );
/// Find contours
findContours( canny_output, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
cout<<(hierarchy.size())<<endl;
}
//corpping and resizing the image
void corpResizeImage(){
int i,j;
Vec3b intensity;
intensity.val[0] = 0;
intensity.val[1] = 0;
intensity.val[2] = 0;
cv::Rect myROI(src.cols/6,0, 2*src.cols/3, src.rows);
Mat croppedImage = src(myROI);
Size size(300,600);
resize(croppedImage,src,size);//resize image
for(i = 0;i < src.rows;++i){
j = 0;
if((i < src.rows/25)||(i < (src.rows/25))){
for(j = 0;j < src.cols;++j){
src.at<Vec3b>(i,j)= intensity;
}
}
}
}
/** #function main */
int main( int argc, char ** argv )
{
loadImage("img/3h.png");
corpResizeImage();
detectImages();
/// Create Window
char* source_window = "Source";
namedWindow( source_window, CV_WINDOW_AUTOSIZE );
imshow( source_window, canny_output );
waitKey(0);
return(0);
}