In openCV I want to compare two histograms. First I transform Bitmap to Mat:
Bitmap puzzleBmp = BitmapFactory.decodeFile(photoPath, options)
mat = new Mat(puzzleBmp.getHeight(), puzzleBmp.getWidth(), CvType.CV_8U, new Scalar(4));
Utils.bitmapToMat(puzzleBmp, mat);
Next I want to create histogram of this image:
Mat mRgba = new Mat();
Imgproc.cvtColor(mat, mRgba, Imgproc.COLOR_RGBA2RGB);
Imgproc.GaussianBlur(mRgba, mRgba, new Size(5, 5), 0, Imgproc.BORDER_DEFAULT);
Mat mHSV = new Mat();
Imgproc.cvtColor(mRgba, mHSV, Imgproc.COLOR_RGB2HSV_FULL);
Mat hist = new Mat();
int h_bins = 30;
int s_bins = 32;
MatOfInt mHistSize = new MatOfInt (h_bins, s_bins);
MatOfFloat mRanges = new MatOfFloat(0, 179, 0, 255);
MatOfInt mChannels = new MatOfInt(0, 1);
List<Mat> lHSV = Arrays.asList(mHSV);
Mat mask2 = new Mat();
mask2 = Mat.zeros( mRgba.rows() + 2, mRgba.cols() + 2, CvType.CV_8UC1 );
Range rowRange = new Range( 1, mask2.rows() - 1 );
Range colRange = new Range( 1, mask2.cols() - 1 );
Mat mask = new Mat();
mask = mask2.submat(rowRange, colRange);
boolean accumulate = false;
Imgproc.calcHist(lHSV, mChannels, mask, hist, mHistSize, mRanges, accumulate);
Core.normalize(hist, hist, 0, 255, Core.NORM_MINMAX, -1, new Mat());
From this part I get hist. But when I make these transformations with two different images i always get from method Imgproc.compareHist() same values, which means they are the same pictures.
Related
I'm working on Android and OpenCV 3.2, I want to apply the perspective transform but I have some trouble
I referenced to this official document OpenCV (go to perspective transform example ) http://docs.opencv.org/trunk/da/d6e/tutorial_py_geometric_transformations.html
but i get a rotated image result 90° or 180°
intput img = [input img ][2] output img output image 90 ° output 2 [output image 180 °][4]
this is my code
public void prespective(Bitmap img){
Mat imgSrc = new Mat();
Bitmap bmp32 = img.copy(Bitmap.Config.ARGB_8888, true);
Utils.bitmapToMat(bmp32, imgSrc);
Mat gray = new Mat();
cvtColor( imgSrc, gray, COLOR_RGBA2GRAY ); //Convert to gray
Mat thr = new Mat();
threshold( gray, thr, 125, 255, THRESH_BINARY ); //Threshold the gray
List<MatOfPoint> contours = new LinkedList<>(); // Vector for storing contours
findContours( thr, contours,new Mat(), RETR_CCOMP, CHAIN_APPROX_SIMPLE ); // Find the contours in the image
MatOfPoint m = biggestCountousMatOfPoint(contours);
RotatedRect box = Imgproc.minAreaRect(new MatOfPoint2f(m.toArray()));
Rect destImageRect = box.boundingRect();
Mat destImage = new Mat(destImageRect.size(),imgSrc.type());
final Point[] pts = new Point[4];
box.points(pts);
Mat _src = new MatOfPoint2f(pts[0], pts[1], pts[2], pts[3]);
Mat _dst = new MatOfPoint2f(new Point(0, 0), new Point(destImage.width() - 1, 0), new Point(destImage.width() - 1, destImage.height() - 1), new Point(0, destImage.height() - 1));
Mat perspectiveTransform=Imgproc.getPerspectiveTransform(_src, _dst);
Imgproc.warpPerspective(imgSrc, destImage, perspectiveTransform, destImage.size());
if(destImage.height() > 0 && destImage.width() > 0) {
Bitmap cinBitmapRotated = Bitmap.createBitmap(destImage.width(), destImage.height(), Bitmap.Config.ARGB_8888);
if (cinBitmapRotated != null) {
Utils.matToBitmap(destImage, cinBitmapRotated);
prenom2Cin.setImageBitmap(cinBitmapRotated);
}
}
}
what's the problem in my code ?
I am new to image processing and I cant get fillPoly() working. Also, drawContours() is leaving some spaces while drawing contours. I am working on Android and most of the references that are given on internet are of Python, Matlab or C++
sSize5 = new Size(5, 5);
mIntermediateMat = new Mat();
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.contours_in_contours_red);
Mat rgba = new Mat(bmp.getHeight(), bmp.getWidth(), CvType.CV_8UC1);
Utils.bitmapToMat(bmp, rgba);
Mat greyInnerWindow;
greyInnerWindow = new Mat();
Mat mRgba = new Mat();
Imgproc.cvtColor(rgba, greyInnerWindow, Imgproc.COLOR_RGBA2GRAY);
Imgproc.GaussianBlur(greyInnerWindow, greyInnerWindow, sSize5, 2, 2);
Imgproc.Canny(greyInnerWindow, mIntermediateMat, 5, 35);
Imgproc.cvtColor(mIntermediateMat, mRgba, Imgproc.COLOR_GRAY2BGRA, 4);
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(mIntermediateMat, contours, mHierarchy, Imgproc.RETR_EXTERNAL,
Imgproc.CHAIN_APPROX_SIMPLE);
for( int i = 0; i< contours.size(); i++ )
{
Imgproc.drawContours(rgba, contours, i, new Scalar(0, 255, 0), -1);
Imgproc.fillPoly(rgba, contours, new Scalar(0,255,0));
}
Bitmap resultBitmap = Bitmap.createBitmap(rgba.cols(), rgba.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(rgba, resultBitmap);
imageView.setImageBitmap(resultBitmap);
Currently I'm developing an app that will detect colored circles. I'm trying to do this by following this tutorial, where guy detects red circles on image with Python. I've written the same code, just for Java.
Mat mat = new Mat(bitmap.getWidth(), bitmap.getHeight(),
CvType.CV_8UC3);
Mat hsv_image = new Mat();
Utils.bitmapToMat(bitmap, mat);
Imgproc.cvtColor(mat, hsv_image, Imgproc.COLOR_BGR2HSV);
Mat lower_red_hue_range = new Mat();
Mat upper_red_hue_range = new Mat();
Core.inRange(hsv_image, new Scalar(0, 100, 100), new Scalar(10, 255, 255), lower_red_hue_range);
Core.inRange(hsv_image, new Scalar(160, 100, 100), new Scalar(179, 255, 255), upper_red_hue_range);
Utils.matToBitmap(hsv_image, bitmap);
mutableBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
image.setImageBitmap(mutableBitmap);
Image I use is identical to one from tutorial:
This is image with applied BGR2HSV:
When I execute the code using lower red hue range, it detects the blue circle. When I use upper red hue range it gives me black bmp(doesn't detect anything). How can it be? What am I doing wrong? This is literally copy moved from python to Java. Why's the result different then?
Thanks in advance.
Your mat is of CvType.CV_8UC1 image, i.e. you are working on a grayscale image. Try with CvType.CV_8UC3
Mat mat = new Mat(bitmap.getWidth(), bitmap.getHeight(), CvType.CV_8UC3);
hsv_image should look like this:
How to select a custom range:
You may want to detect a green circle.
Well, in HSV, tipically the range is:
H in [0,360]
S,V in [0,100]
However, for CV_8UC3 images, each component H,S,V can be represented by only 256 values at most, since it's stored in 1 byte. So, in OpenCV, the ranges H,S,V for CV_8UC3 are:
H in [0,180] <- halved to fit in the range
S,V in [0,255] <- stretched to fit the range
So to switch from typical range to OpenCV range you need to:
opencv_H = typical_H / 2;
opencv_S = typical_S * 2.55;
opencv_V = typical_V * 2.55;
So, green colors are around the value of hue of 120. The hue can have a value in the interval [0,360].
However, for Mat3b HSV images, the range for H is in [0,180], i.e. is halved so it can fit in a 8 bit representation with at most 256 possible values.
So, you want the H value to be around 120 / 2 = 60, say from 50 to 70.
You also set a minimum value for S,V to 100 in order to prevent very dark (almost black) colors.
Mat green_hue_range
inRange(hsv_image, cv::Scalar(50, 100, 100), cv::Scalar(70, 255, 255), green_hue_range);
use the following code and pass color to Blob detector and then pass an image to the detector
private Scalar converScalarRgba2HSV(Scalar rgba) {
Mat pointMatHsv= new Mat();
Mat pointMatRgba = new Mat(1, 1, CvType.CV_8UC3, rgba);
Imgproc.cvtColor(pointMatRgba,pointMatHsv, Imgproc.COLOR_RGB2HSV_FULL, 4);
return new Scalar(pointMatHsv.get(0, 0));}
// Blob Detector
public class ColorBlobDetector {
// Lower and Upper bounds for range checking in HSV color space
private Scalar mLowerBound = new Scalar(0);
private Scalar mUpperBound = new Scalar(0);
// Minimum contour area in percent for contours filtering
private static double mMinContourArea = 0.1;
// Color radius for range checking in HSV color space
private Scalar mColorRadius = new Scalar(25,50,50,0);
private Mat mSpectrum = new Mat();
private List<MatOfPoint> mContours = new ArrayList<MatOfPoint>();
Mat mPyrDownMat = new Mat();
Mat mHsvMat = new Mat();
Mat mMask = new Mat();
Mat mDilatedMask = new Mat();
Mat mHierarchy = new Mat();
public void setColorRadius(Scalar radius) {
mColorRadius = radius;
}
public void setHsvColor(Scalar hsvColor) {
double minH = (hsvColor.val[0] >= mColorRadius.val[0]) ? hsvColor.val[0]-mColorRadius.val[0] : 0;
double maxH = (hsvColor.val[0]+mColorRadius.val[0] <= 255) ? hsvColor.val[0]+mColorRadius.val[0] : 255;
mLowerBound.val[0] = minH;
mUpperBound.val[0] = maxH;
mLowerBound.val[1] = hsvColor.val[1] - mColorRadius.val[1];
mUpperBound.val[1] = hsvColor.val[1] + mColorRadius.val[1];
mLowerBound.val[2] = hsvColor.val[2] - mColorRadius.val[2];
mUpperBound.val[2] = hsvColor.val[2] + mColorRadius.val[2];
mLowerBound.val[3] = 0;
mUpperBound.val[3] = 255;
Mat spectrumHsv = new Mat(1, (int)(maxH-minH), CvType.CV_8UC3);
for (int j = 0; j < maxH-minH; j++) {
byte[] tmp = {(byte)(minH+j), (byte)255, (byte)255};
spectrumHsv.put(0, j, tmp);
}
Imgproc.cvtColor(spectrumHsv, mSpectrum, Imgproc.COLOR_HSV2RGB_FULL, 4);
}
public Mat getSpectrum() {
return mSpectrum;
}
public void setMinContourArea(double area) {
mMinContourArea = area;
}
public void process(Mat rgbaImage) {
Imgproc.pyrDown(rgbaImage, mPyrDownMat);
Imgproc.pyrDown(mPyrDownMat, mPyrDownMat);
Imgproc.cvtColor(mPyrDownMat, mHsvMat, Imgproc.COLOR_RGB2HSV_FULL);
Core.inRange(mHsvMat, mLowerBound, mUpperBound, mMask);
Imgproc.dilate(mMask, mDilatedMask, new Mat());
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(mDilatedMask, contours, mHierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
// Find max contour area
double maxArea = 0;
Iterator<MatOfPoint> each = contours.iterator();
while (each.hasNext()) {
MatOfPoint wrapper = each.next();
double area = Imgproc.contourArea(wrapper);
if (area > maxArea)
maxArea = area;
}
// Filter contours by area and resize to fit the original image size
mContours.clear();
each = contours.iterator();
while (each.hasNext()) {
MatOfPoint contour = each.next();
if (Imgproc.contourArea(contour) > mMinContourArea*maxArea) {
Core.multiply(contour, new Scalar(4,4), contour);
mContours.add(contour);
}
}
}
public List<MatOfPoint> getContours() {
return mContours;
}}
now set detector
public void initDetector() {
mDetector = new ColorBlobDetector();
mSpectrum = new Mat();
mBlobColorRgba = new Scalar(255);
mBlobColorHsv = new Scalar(255);
SPECTRUM_SIZE = new org.opencv.core.Size(500, 64);
CONTOUR_COLOR = new Scalar(0, 255, 0, 255);
mDetector.setHsvColor(converScalarRgba2HSV(new Scalar(0,255,255,255)));
Imgproc.resize(mDetector.getSpectrum(), mSpectrum, SPECTRUM_SIZE, 0, 0, Imgproc.INTER_LINEAR_EXACT);
mIsColorSelected = true;
}
now pass an image to a detector object
Mat mRgba = new Mat(inputFrame.height(), inputFrame.width(), CvType.CV_8UC4);
mRgba = inputFrame;
mDetector.process(mRgba);
List<MatOfPoint> contours = mDetector.getContours();
Log.e(TAG, "Contours count: " + contours.size());
drawContours(mRgba, contours, -1, CONTOUR_COLOR);
return mRgba;
Happy Codeing !!!
I'm trying to train my svm with 4 image. all of my images are 300*400. I resize them to 304*400 so i can get the HOGDescriptor of my images because of 16*16 block. then I use Core.hconcat(mats, trainData) to gather all of my images into one Mat. after that when I try to set lables for my trainData, in train part I get below Error. I'm new to openCV. what is wrong?
Mat rose1 = new Mat();
Mat rose2 = new Mat();
Mat rose3 = new Mat();
Mat rose4 = new Mat();
Mat rose5 = new Mat();
try {
rose1 = org.opencv.android.Utils.loadResource(
getApplicationContext(), R.drawable.rose1);
rose2 = org.opencv.android.Utils.loadResource(
getApplicationContext(), R.drawable.rose2);
rose3 = org.opencv.android.Utils.loadResource(
getApplicationContext(), R.drawable.rose3);
rose4 = org.opencv.android.Utils.loadResource(
getApplicationContext(), R.drawable.rose4);
rose5 = org.opencv.android.Utils.loadResource(
getApplicationContext(), R.drawable.rose5);
} catch (IOException e) {
e.printStackTrace();
}
Mat rose1Resized = new Mat();
Mat rose2Resized = new Mat();
Mat rose3Resized = new Mat();
Mat rose4Resized = new Mat();
Size sz = new Size(304, 400);
Imgproc.resize(rose1, rose1Resized, sz);
Imgproc.resize(rose2, rose2Resized, sz);
Imgproc.resize(rose3, rose3Resized, sz);
Imgproc.resize(rose4, rose4Resized, sz);
// HOG
MatOfFloat rose1Float = new MatOfFloat();
MatOfFloat rose2Float = new MatOfFloat();
MatOfFloat rose3Float = new MatOfFloat();
MatOfFloat rose4Float = new MatOfFloat();
HOGDescriptor hog = new HOGDescriptor(new Size(304, 400), new Size(16,
16), new Size(new Point(8, 8)), new Size(new Point(8, 8)), 9);
hog.compute(rose1Resized, rose1Float);
hog.compute(rose2Resized, rose2Float);
hog.compute(rose3Resized, rose3Float);
hog.compute(rose4Resized, rose4Float);
ArrayList<Mat> mats = new ArrayList<>();
mats.add(rose1Float);
mats.add(rose2Float);
mats.add(rose3Float);
mats.add(rose4Float);
// SVM
Mat trainData = new Mat();
Core.hconcat(mats, trainData);
float[] lableFloat = { 1, 1, 1, 1 };
Mat lables = new Mat(1, 4, CvType.CV_32FC1);
lables.put(0, 0, lableFloat);
CvSVM svm = new CvSVM();
CvSVMParams params = new CvSVMParams();
params.set_svm_type(CvSVM.C_SVC);
params.set_kernel_type(CvSVM.LINEAR);
params.set_term_crit(new TermCriteria(TermCriteria.EPS, 100, 1e-6));
svm.train(trainData, lables, new Mat(), new Mat(), params);
Error is:
E/AndroidRuntime(27347): CvException [org.opencv.core.CvException: cv::Exception: /home/reports/ci/slave_desktop/50-SDK/opencv/modules/ml/src/inner_functions.cpp:671: error: (-209) Response array must contain as many elements as the total number of samples in function cvPreprocessCategoricalResponses
first of all i reshape MatOfFloat after get HOG. because rose1Float was 65268*1 and i need it in one row Mat.
Mat roseReshaped1 = rose1Float.reshape(1, 1);
Mat roseReshaped2 = rose2Float.reshape(1, 1);
Mat roseReshaped3 = rose3Float.reshape(1, 1);
Mat roseReshaped4 = rose4Float.reshape(1, 1);
then i used push_back instead of "Core.hconcat(mats, trainData)"
Mat trainData = new Mat(0, sizeOfCols, CvType.CV_32FC1);
trainData.push_back(roseReshaped1);
trainData.push_back(roseReshaped2);
trainData.push_back(roseReshaped3);
trainData.push_back(roseReshaped4);
my trainData would be 4*65268 and this is my label. or as opencv say, response!
int[] l = { 1, 2, 3, 4 };
Mat lables = new Mat(4, 1, CvType.CV_32SC1);
lables.put(0, 0, l);
now everything works perfectly fine. Thanks to #berak.
I want to compare two pictures similarity
Code:
Mat mat1=Highgui.imread("/mnt/sdcard/91.png");
Mat mat2=Highgui.imread("/mnt/sdcard/92.png");
double distance = Imgproc.compareHist(mat1, mat2, Imgproc.CV_COMP_CORREL); //(this line throws an exception)
Exception information:
01-30 10:48:20.203: E/AndroidRuntime(3540): Caused by: CvException
[org.opencv.core.CvException:
/home/andreyk/OpenCV2/trunk/opencv/modules/imgproc/src/histogram.cpp:1387:
error: (-215) H1.type() == H2.type() && H1.type() == CV_32F in
function double cv::compareHist(const cv::_InputArray&, const
cv::_InputArray&, int)
Can anybody help me? How should I solve this?
At first make sure that both images have 1 channel (if not, than convert them to grayscale with cvtColor or choose one channel witn cvSplit) and have one type, for instance, CV_8UC1.
Then calculate histograms of this images.
Example of code:
int histSize = 180;
float range[] = {0, 180};
const float* histRange = {range};
bool uniform = true;
bool accumulate = false;
cv::Mat hist1, hist2;
cv::calcHist(&mat1, 1, 0, cv::Mat(), hist1, 1, &histSize, &histRange, uniform, accumulate );
cv::calcHist(&mat2, 1, 0, cv::Mat(), hist2, 1, &histSize, &histRange, uniform, accumulate );
double result = cv::compareHist( hist1, hist2, CV_COMP_CORREL);
On Android the code would be similar to:
Mat image0 = ...; //
Mat image1 = ...;
Mat hist0 = new Mat();
Mat hist1 = new Mat();
int hist_bins = 30; //number of histogram bins
int hist_range[]= {0,180};//histogram range
MatOfFloat ranges = new MatOfFloat(0f, 256f);
MatOfInt histSize = new MatOfInt(25);
Imgproc.calcHist(Arrays.asList(image0), new MatOfInt(0), new Mat(), hist0, histSize, ranges);
Imgproc.calcHist(Arrays.asList(image1), new MatOfInt(0), new Mat(), hist1, histSize, ranges);
double res = Imgproc.compareHist(image0, image01, Imgproc.CV_COMP_CORREL);
#skornos your code is wrong.
It should be
Mat image0 = ...; //
Mat image1 = ...;
Mat hist0 = new Mat();
Mat hist1 = new Mat();
int hist_bins = 30; //number of histogram bins
int hist_range[]= {0,180};//histogram range
MatOfFloat ranges = new MatOfFloat(0f, 256f);
MatOfInt histSize = new MatOfInt(25);
Imgproc.calcHist(Arrays.asList(image0), new MatOfInt(0), new Mat(), hist0, histSize, ranges);
Imgproc.calcHist(Arrays.asList(image1), new MatOfInt(0), new Mat(), hist1, histSize, ranges);
double res = Imgproc.compareHist(hist0, hist1, Imgproc.CV_COMP_CORREL);
Note the last line, it should be hist0 compare to hist1 not comparing images
Mat hsvRef = new Mat();
Mat hsvCard = new Mat();
Mat srcRef = new Mat(refImage.getHeight(), refImage.getWidth(), CvType.CV_8UC2);
Utils.bitmapToMat(refImage, srcRef);
Mat srcCard = new Mat(cardImage.getHeight(), cardImage.getWidth(), CvType.CV_8UC2);
Utils.bitmapToMat(cardImage, srcCard);
/// Convert to HSV
Imgproc.cvtColor(srcRef, hsvRef, Imgproc.COLOR_BGR2HSV);
Imgproc.cvtColor(srcCard, hsvCard, Imgproc.COLOR_BGR2HSV);
/// Using 50 bins for hue and 60 for saturation
int hBins = 50;
int sBins = 60;
MatOfInt histSize = new MatOfInt( hBins, sBins);
// hue varies from 0 to 179, saturation from 0 to 255
MatOfFloat ranges = new MatOfFloat( 0f,180f,0f,256f );
// we compute the histogram from the 0-th and 1-st channels
MatOfInt channels = new MatOfInt(0, 1);
Mat histRef = new Mat();
Mat histCard = new Mat();
ArrayList<Mat> histImages=new ArrayList<Mat>();
histImages.add(hsvRef);
Imgproc.calcHist(histImages,
channels,
new Mat(),
histRef,
histSize,
ranges,
false);
Core.normalize(histRef,
histRef,
0,
1,
Core.NORM_MINMAX,
-1,
new Mat());
histImages=new ArrayList<Mat>();
histImages.add(hsvCard);
Imgproc.calcHist(histImages,
channels,
new Mat(),
histCard,
histSize,
ranges,
false);
Core.normalize(histCard,
histCard,
0,
1,
Core.NORM_MINMAX,
-1,
new Mat());
double resp1 = Imgproc.compareHist(histRef, histCard, 0);
Log.d(TAG, "HIST COMPARE 0" + resp1);
double resp2 = Imgproc.compareHist(histRef, histCard, 1);
Log.d(TAG, "HIST COMPARE 1" + resp2);
double resp3 = Imgproc.compareHist(histRef, histCard, 2);
Log.d(TAG, "HIST COMPARE 2" + resp3);
double resp4 = Imgproc.compareHist(histRef, histCard, 3);
Log.d(TAG, "HIST COMPARE 3" + resp4);