Rotate area to align the major axis horizontally with opencv - c++

Please can someone here who can help me with this. I'm trying to rotate a segmented region of an image to align the major axis horizontally.
I have a segmented region in the center of the image following the steps used herein. Move area of an image to the center using OpenCV
I read this OPENCV: PCA application error in image_proc, but it does not help me solve my problem.
I have this
I want this

Slightly different than how Miki suggested, I used findNonZero, minAreaRect, and WarpAffine.
You can either use 270 or 90 on the getRotationMatrix2D to align the major axis with the horizontal.
#include "stdafx.h"
#include <opencv/cxcore.h>
#include <opencv2\core\mat.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <opencv/cxcore.h>
#include <opencv/highgui.h>
#include <opencv/cv.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/videoio/videoio.hpp>
using namespace cv;
using namespace std;
int main() {
//getting the image
Mat image = imread("C:/this/is/a/path/to/an/image.png");
//create new image that looks exactly like old image
Mat rot_image = image.clone();
rot_image = Scalar(0);
//showing the image
namedWindow("Image", CV_WINDOW_NORMAL| CV_WINDOW_KEEPRATIO | CV_GUI_EXPANDED);
namedWindow("Rotated Image", CV_WINDOW_NORMAL| CV_WINDOW_KEEPRATIO | CV_GUI_EXPANDED);
imshow("Image", image);
waitKey(0);
imshow("Rotated Image", rot_image);
waitKey(0);
//convert image
Mat img_bw;
inRange(image, Scalar(1,1,1), Scalar(255,255,255), img_bw);
imshow("Rotated Image", img_bw);
waitKey(0);
//find coordinates
Mat nonZeroCoordinates;
findNonZero(img_bw, nonZeroCoordinates);
RotatedRect rect = minAreaRect(nonZeroCoordinates);
rect.center = Point(image.cols/2, image.rows/2);
//get the Rotation Matrix
Mat M = getRotationMatrix2D(rect.center, 270, 1.0);
// perform the affine transformation
warpAffine(image, rot_image, M, image.size(), INTER_CUBIC);
//displaying the image
imshow("Rotated Image", rot_image);
waitKey(0);
//saving the new image
imwrite("C:/this/is/a/path/to/a/rotatedImage.png", rot_image);
}
That code turns this:
to this:
You can take the rect.center line out if you're sure your object is already going to be in the center.

Related

Isolate image shadow with OpenCV C++

I have seen some algorithms on how to remove a shadow from an image using OpenCV with C++. I have looked around but haven't find the way to not just erase the shadow, but store it on a new image alone.
What I am doing with this code is to convert the original image (that I obtained from the Internet) to the HSV color space, change the value of V=180, which somehow removes the shadow, and then converting the image back to the BGR color space. I am clueless on how to 'extract' the removed shadow and save it to a different image...
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat srcImg;
Mat hsvImg;
Mat bgrImg;
srcImg = imread("pcb-2008.jpg");
cvtColor(srcImg, hsvImg, CV_BGR2HSV);
imwrite("1.hsv.jpg", hsvImg);
Mat channel[3];
split(hsvImg, channel);
channel[2] = Mat(hsvImg.rows, hsvImg.cols, CV_8UC1, 180);
merge(channel, 3, hsvImg);
imwrite("2.hsvNoShadow.jpg", hsvImg);
cvtColor(hsvImg, bgrImg, CV_HSV2BGR);
imwrite("3.backToBgr.jpg", bgrImg);
return 0;
}
Sample image of a PCB

OpenCV SIFT key points extraction isuue

I tried to extract SIFT key points. It is working fine for a sample image I downloaded (height 400px width 247px horizontal and vertical resolutions 300dpi). Below image shows the extracted points.
Then I tried to apply the same code to a image that was taken and edited by me (height 443px width 541px horizontal and vertical resolutions 72dpi).
To create the above image I rotated the original image then removed its background and resized it using Photoshop, but my code, for that image doesn't extract features like in the first image.
See the result :
It just extract very few points. I expect a result as in the first case.
For the second case when I'm using the original image without any edit the program gives points as the first case.
Here is the simple code I have used
#include<opencv\cv.h>
#include<opencv\highgui.h>
#include<opencv2\nonfree\nonfree.hpp>
using namespace cv;
int main(){
Mat src, descriptors,dest;
vector<KeyPoint> keypoints;
src = imread(". . .");
cvtColor(src, src, CV_BGR2GRAY);
SIFT sift;
sift(src, src, keypoints, descriptors, false);
drawKeypoints(src, keypoints, dest);
imshow("Sift", dest);
cvWaitKey(0);
return 0;
}
What I'm doing wrong here? what do I need to do to get a result like in the first case to my own image after resizing ?
Thank you!
Try set nfeatures parameter (may be other parameters also need adjustment) in SIFT constructor.
Here is constructor definition from reference:
SIFT::SIFT(int nfeatures=0, int nOctaveLayers=3, double contrastThreshold=0.04, double edgeThreshold=10, double sigma=1.6)
Your code will be:
#include<opencv\cv.h>
#include<opencv\highgui.h>
#include<opencv2\nonfree\nonfree.hpp>
using namespace cv;
using namespace std;
int main(){
Mat src, descriptors,dest;
vector<KeyPoint> keypoints;
src = imread("D:\\ImagesForTest\\leaf.jpg");
cvtColor(src, src, CV_BGR2GRAY);
SIFT sift(2000,3,0.004);
sift(src, src, keypoints, descriptors, false);
drawKeypoints(src, keypoints, dest);
imshow("Sift", dest);
cvWaitKey(0);
return 0;
}
The result:
Dense sampling example:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp>
#include "opencv2/nonfree/nonfree.hpp"
int main(int argc, char* argv[])
{
cv::initModule_nonfree();
cv::namedWindow("result");
cv::Mat bgr_img = cv::imread("D:\\ImagesForTest\\lena.jpg");
if (bgr_img.empty())
{
exit(EXIT_FAILURE);
}
cv::Mat gray_img;
cv::cvtColor(bgr_img, gray_img, cv::COLOR_BGR2GRAY);
cv::normalize(gray_img, gray_img, 0, 255, cv::NORM_MINMAX);
cv::DenseFeatureDetector detector(12.0f, 1, 0.1f, 10);
std::vector<cv::KeyPoint> keypoints;
detector.detect(gray_img, keypoints);
std::vector<cv::KeyPoint>::iterator itk;
for (itk = keypoints.begin(); itk != keypoints.end(); ++itk)
{
std::cout << itk->pt << std::endl;
cv::circle(bgr_img, itk->pt, itk->size, cv::Scalar(0,255,255), 1, CV_AA);
cv::circle(bgr_img, itk->pt, 1, cv::Scalar(0,255,0), -1);
}
cv::Ptr<cv::DescriptorExtractor> descriptorExtractor = cv::DescriptorExtractor::create("SURF");
cv::Mat descriptors;
descriptorExtractor->compute( gray_img, keypoints, descriptors);
// SIFT returns large negative values when it goes off the edge of the image.
descriptors.setTo(0, descriptors<0);
imshow("result",bgr_img);
cv::waitKey();
return 0;
}
The result:

Image edge smoothing with opencv

I am trying to smooth output image edges using opencv framework, I am trying following steps. Steps took from here https://stackoverflow.com/a/17175381/790842
int lowThreshold = 10.0;
int ratio = 3;
int kernel_size = 3;
Mat src_gray,detected_edges,dst,blurred;
/// Convert the image to grayscale
cvtColor( result, src_gray, CV_BGR2GRAY );
/// Reduce noise with a kernel 3x3
cv::blur( src_gray, detected_edges, cv::Size(5,5) );
/// Canny detector
cv::Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );
//Works fine upto here I am getting perfect edge mask
cv::dilate(detected_edges, blurred, result);
//I get Assertion failed (src.channels() == 1 && func != 0) in countNonZero ERROR while doing dilate
result.copyTo(blurred, blurred);
cv::blur(blurred, blurred, cv::Size(3.0,3.0));
blurred.copyTo(result, detected_edges);
UIImage *image = [UIImageCVMatConverter UIImageFromCVMat:result];
I want help whether if I am going in right way, or what am I missing?
Thanks for any suggestion and help.
Updated:
I have got an image like below got from grabcut algorithm, now I want to apply edge smoothening to the image, as you can see the image is not smooth.
Do you want to get something like this?
If yes, then here is the code:
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main(int argc, char **argv)
{
cv::namedWindow("result");
Mat img=imread("TestImg.png");
Mat whole_image=imread("D:\\ImagesForTest\\lena.jpg");
whole_image.convertTo(whole_image,CV_32FC3,1.0/255.0);
cv::resize(whole_image,whole_image,img.size());
img.convertTo(img,CV_32FC3,1.0/255.0);
Mat bg=Mat(img.size(),CV_32FC3);
bg=Scalar(1.0,1.0,1.0);
// Prepare mask
Mat mask;
Mat img_gray;
cv::cvtColor(img,img_gray,cv::COLOR_BGR2GRAY);
img_gray.convertTo(mask,CV_32FC1);
threshold(1.0-mask,mask,0.9,1.0,cv::THRESH_BINARY_INV);
cv::GaussianBlur(mask,mask,Size(21,21),11.0);
imshow("result",mask);
cv::waitKey(0);
// Reget the image fragment with smoothed mask
Mat res;
vector<Mat> ch_img(3);
vector<Mat> ch_bg(3);
cv::split(whole_image,ch_img);
cv::split(bg,ch_bg);
ch_img[0]=ch_img[0].mul(mask)+ch_bg[0].mul(1.0-mask);
ch_img[1]=ch_img[1].mul(mask)+ch_bg[1].mul(1.0-mask);
ch_img[2]=ch_img[2].mul(mask)+ch_bg[2].mul(1.0-mask);
cv::merge(ch_img,res);
cv::merge(ch_bg,bg);
imshow("result",res);
cv::waitKey(0);
cv::destroyAllWindows();
}
And I think this link will be interestiong for you too: Poisson Blending
I have followed the following steps to smooth the edges of the Foreground I got from GrabCut.
Create a binary image from the mask I got from GrabCut.
Find the contour of the binary image.
Create an Edge Mask by drawing the contour points. It gives the boundary edges of the Foreground image I got from GrabCut.
Then follow the steps define in https://stackoverflow.com/a/17175381/790842

Image Contour Detection Error: OpenCV, C++

I am trying to write a program to detect contours within an image using OpenCV in the C++ environment.
The problem with it is that I don't get a compile error, but instead a runtime error. I have no idea why; I followed the book and OpenCV documentation sources to build the code below and it should work fine but it doesn't... any ideas on what might be wrong...?
#include "iostream"
#include<opencv\cv.h>
#include<opencv\highgui.h>
#include<opencv\ml.h>
#include<opencv\cxcore.h>
#include <iostream>
#include <string>
#include <opencv2/core/core.hpp> // Basic OpenCV structures (cv::Mat)
#include <opencv2/highgui/highgui.hpp> // Video write
using namespace cv;
using namespace std;
Mat image; Mat image_gray; Mat image_gray2; Mat threshold_output;
int thresh=100, max_thresh=255;
int main(int argc, char** argv) {
//Load Image
image =imread("C:/Users/Tomazi/Pictures/Opencv/ayo.bmp");
//Convert Image to gray & blur it
cvtColor( image,
image_gray,
CV_BGR2GRAY );
blur( image_gray,
image_gray2,
Size(3,3) );
//Threshold Gray&Blur Image
threshold(image_gray2,
threshold_output,
thresh,
max_thresh,
THRESH_BINARY);
//2D Container
vector<vector<Point>> contours;
//Fnd Countours Points, (Imput Image, Storage, Mode1, Mode2, Offset??)
findContours(threshold_output,
contours, // a vector of contours
CV_RETR_EXTERNAL, // retrieve the external contours
CV_CHAIN_APPROX_NONE,
Point(0, 0)); // all pixels of each contours
// Draw black contours on a white image
Mat result(threshold_output.size(),CV_8U,Scalar(255));
drawContours(result,contours,
-1, // draw all contours
Scalar(0), // in black
2); // with a thickness of 2
//Create Window
char* DisplayWindow = "Source";
namedWindow(DisplayWindow, CV_WINDOW_AUTOSIZE);
imshow(DisplayWindow, contours);
waitKey(0);
return 1;
}
I bet that you are using the MSVC IDE. Anyway, your code has a lot of problems and I've covered most of them on Stackoverflow. Here they go:
Escape the slashes
Code safely and check the return of the calls
How Visual Studio loads files at runtime
I suspect that your problem is that imread() is failing because it didn't found the file. The links above will help you fix that.

Drawing Bounding-Box using OpenCV in C++ Enviroment

Hello peeps I have developed a piece of software that draws contours of the input image, now I wont to take this to the next level and draw Bounding Box around objects of interest i.e. A person. I looked at boundingRect() function but i am struggling to understand it. Maybe there are different functions algorithms draw Bounding Box.....?
Here is the code of my program:
#include "iostream"
#include<opencv\cv.h>
#include<opencv\highgui.h>
#include<opencv\ml.h>
#include<opencv\cxcore.h>
#include <iostream>
#include <string>
#include <opencv2/core/core.hpp> // Basic OpenCV structures (cv::Mat)
#include <opencv2/highgui/highgui.hpp> // Video write
using namespace cv;
using namespace std;
Mat image; Mat image_gray; Mat image_gray2; Mat threshold_output;
int thresh=100, max_thresh=255;
int main(int argc, char** argv) {
//Load Image
image =imread("C:/Users/Tomazi/Pictures/Opencv/tomazi.bmp");
//Convert Image to gray & blur it
cvtColor( image,
image_gray,
CV_BGR2GRAY );
blur( image_gray,
image_gray2,
Size(3,3) );
//Threshold Gray&Blur Image
threshold(image_gray2,
threshold_output,
thresh,
max_thresh,
THRESH_BINARY);
//2D Container
vector<vector<Point>> contours;
//Fnd Countours Points, (Imput Image, Storage, Mode1, Mode2, Offset??)
findContours(threshold_output,
contours, // a vector of contours
CV_RETR_EXTERNAL,// retrieve the external contours
CV_CHAIN_APPROX_NONE,
Point(0, 0)); // all pixels of each contours
// Draw black contours on a white image
Mat result(threshold_output.size(),CV_8U,Scalar(255));
drawContours(result,contours,
-1, // draw all contours
Scalar(0), // in black
2); // with a thickness of 2
//Create Window
char* DisplayWindow = "Source";
namedWindow(DisplayWindow, CV_WINDOW_AUTOSIZE);
imshow(DisplayWindow, result);
waitKey(5000);
return 1;
}
Can anyone suggest an solution...? Perhaps direct me to some sources, tutorials etc. Reading OpenCV documentation and looking at the boundingRect() function i still dont understand. HELP PLEASE :)
But you can also easily compute the bounding box yourself and then draw them using the rectangle function:
int maxX = 0, minX = image.cols, maxY=0, minY = image.rows;
for(int i=0; i<contours.size(); i++)
for(int j=0; j<contours[i].size(); j++)
{
Point p = contours[i][j];
maxX = max(maxX, p.x);
minX = min(minX, p.x);
maxY = max(maxY, p.y);
minY = min(minY, p.y);
}
rectangle( result, Point(minX,minY), Point(maxX, maxY), Scalar(0) );
This link was not helpful?
I think it demonstrates how to take the contour object and make it a polygon approximation, plus how to draw the bounding rectangle around it.
It seems to be one of the basic OpenCV demos.
I've talked about the bounding box technique in these posts:
How to detect Text Area from image?
Contours opencv : How to eliminate small contours in a binary image
OpenCv 2.3 C - How to isolate object inside image (simple C++ demo)
I think that the last one can probably help you understand how the standard technique works. What OpenCV offers is an easier approach.