I am trying to find the location of image inside a specific area in another. I am using javacv to do this issue. But my code is giving an error when executing cvMatchTemplate function. I think I am miss using cvSetImageROI.
This is how I am using it:
public static void main(String c[]) {
IplImage src = cvLoadImage("test.jpg", 0);
IplImage tmp = cvLoadImage("tmp.png", 0);
IplImage result = cvCreateImage(cvSize(src.width() - tmp.width() + 1, src.height() - tmp.height() + 1),
IPL_DEPTH_32F,1);
cvZero(result);
cvSetImageROI(src, new CvRect(22, 50, 30, 30));
cvSetImageROI(result, new CvRect(22, 50, 30, 30));
//Match Template Function from OpenCV
cvMatchTemplate(src, tmp, result, CV_TM_CCORR_NORMED);
double[] min_val = new double[2];
double[] max_val = new double[2];
CvPoint minLoc = new CvPoint();
CvPoint maxLoc = new CvPoint();
cvMinMaxLoc(result, min_val, max_val, minLoc, maxLoc,
null);
CvPoint point = new CvPoint();
point.x(maxLoc.x() + tmp.width());
point.y(maxLoc.y() + tmp.height());
cvRectangle(src, maxLoc, point, CvScalar.RED, 2, 8, 0);
cvShowImage("Lena Image", src);
cvWaitKey(0);
cvReleaseImage(src);
cvReleaseImage(tmp);
cvReleaseImage(result);
}
This is the error:
OpenCV Error: Assertion failed (result.size() == cv::Size(std::abs(img.cols - templ.cols)
+ 1,std::abs(img.rows - templ.rows) + 1) && result.type() == CV_32F) in unknown function,
file ..\..\..\src\opencv\modules\imgproc\src\templmatch.cpp, line 384
Any Help?
Hey see this example that I did with Javacv
public class Test {
static Image image;
public static void main(String[] args) throws Exception {
int width = Integer.parseInt(args[3]);
int height = Integer.parseInt(args[4]);
IplImage src = cvLoadImage(
args[0], 0);
IplImage tmp = cvLoadImage(
args[1], 0);
IplImage result = cvCreateImage(
cvSize(src.width() - tmp.width() + 1,
src.height() - tmp.height() + 1), IPL_DEPTH_32F, src.nChannels());
cvZero(result);
// Match Template Function from OpenCV
cvMatchTemplate(src, tmp, result, CV_TM_CCORR_NORMED);
// double[] min_val = new double[2];
// double[] max_val = new double[2];
DoublePointer min_val = new DoublePointer();
DoublePointer max_val = new DoublePointer();
CvPoint minLoc = new CvPoint();
CvPoint maxLoc = new CvPoint();
cvMinMaxLoc(result, min_val, max_val, minLoc, maxLoc, null);
// Get the Max or Min Correlation Value
// System.out.println(Arrays.toString(min_val));
// System.out.println(Arrays.toString(max_val));
CvPoint point = new CvPoint();
point.x(maxLoc.x() + tmp.width());
point.y(maxLoc.y() + tmp.height());
// cvMinMaxLoc(src, min_val, max_val,0,0,result);
cvRectangle(src, maxLoc, point, CvScalar.RED, 2, 8, 0);// Draw a
// Rectangle for
// Matched
// Region
CvRect rect = new CvRect();
rect.x(maxLoc.x());
rect.y(maxLoc.y());
rect.width(tmp.width() + width);
rect.height(tmp.width() + height);
cvSetImageROI(src, rect);
IplImage imageNew = cvCreateImage(cvGetSize(src), src.depth(),
src.nChannels());
cvCopy(src, imageNew);
cvSaveImage(args[2], imageNew);
cvShowImage("Lena Image", src);
cvWaitKey(0);
cvReleaseImage(src);
cvReleaseImage(tmp);
cvReleaseImage(result);
}
full reference here
we need 4 default parameters like this
"C:\Users\Waldema\Desktop\bg.jpg" "C:\Users\Waldema\Desktop\logosiemens.jpg" "C:\Users\Waldema\Desktop\imageToFind.jpg" 100 200
configurable in the Run configurations of common IDEs.
I think that will help
I found the problem it was in setting the roi of the result image, this is the wrong line :
cvSetImageROI(result, new CvRect(22, 50, 30, 30));
It should be like this :
cvSetImageROI(result, new CvRect(22, 50, 30 - tmp.width() + 1, 30 - tmp.height() + 1));
I am not sure why but I think it is because cvMatchTemplate function takes the result dimension equal to the source dimensions minus the template dimensions plus one pixel.
Related
picture of processed image + original
I'm working on a project where I'm taking Smash Bros. game output, taking a screenshot, processing it in order to detect the percents which the characters are sitting at.
The program I wrote is detecting the 57 as a 55 and the 11 (which I let settle to it's normal position) as a 51. And while the gameplay is running, the numbers will jump around.
The program I wrote uses Tess4J, and I've configured everything right. I have trained Tesseract with my own custom font that I made using the games percentage numbers. I've tried multiple different fonts as well. What will make it more accurate!?
I've thought about instead of calculating percents, instead just detecting when they're damaged, but I'm also figuring that out.
This is the code I use to process images:
public static Mat blur(Mat input, int numberOfTimes){
Mat sourceImage = new Mat();
Mat destImage = input.clone();
for(int i=0;i<numberOfTimes;i++){
sourceImage = destImage.clone();
Imgproc.blur(sourceImage, destImage, new Size(3.0, 3.0));
}
return destImage;
}
public static BufferedImage purify(BufferedImage image) {
BufferedImage image2 = ImageHelper.convertImageToGrayscale(image);
Mat mat = BufferedImage2Mat(image2, -1);
Mat resizedMat = new Mat();
double width = mat.cols();
double height = mat.rows();
double aspect = width / height;
Size sz = new Size(width * aspect * 1.4, height * aspect * 1.4);
Imgproc.resize(mat, resizedMat, sz);
double thresh = Imgproc.threshold(resizedMat, resizedMat, 23, 255, Imgproc.THRESH_BINARY_INV);
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3));
Imgproc.dilate(resizedMat, resizedMat, kernel, new Point(0, 0), 9);
return toBufferedImage(HighGui.toBufferedImage(blur(resizedMat, 0)));
}
public static BufferedImage toBufferedImage(Image img)
{
if (img instanceof BufferedImage)
{
return (BufferedImage) img;
}
BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D bGr = bimage.createGraphics();
bGr.drawImage(img, 0, 0, null);
bGr.dispose();
return bimage;
}
public static Image denoise(BufferedImage img) {
Mat image = BufferedImage2Mat(img, 0);
Mat out = new Mat();
Mat tmp = new Mat();
Mat kernel = new Mat(new Size(3, 3), CvType.CV_8UC1, new Scalar(255));
Imgproc.morphologyEx(image, tmp, Imgproc.MORPH_OPEN, kernel);
Imgproc.morphologyEx(tmp, out, Imgproc.MORPH_CLOSE, kernel);
return HighGui.toBufferedImage(out);
}
public static Mat BufferedImage2Mat(BufferedImage image, int filter) {
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", byteArrayOutputStream);
byteArrayOutputStream.flush();
return Imgcodecs.imdecode(new MatOfByte(byteArrayOutputStream.toByteArray()), filter);
} catch (IOException e) {
return null;
}
}
public static Image clean(BufferedImage image) {
Mat og = BufferedImage2Mat(image, Imgcodecs.IMREAD_UNCHANGED);
Mat im = BufferedImage2Mat(image, 0);
Mat bw = new Mat(im.size(), CvType.CV_8U);
Imgproc.threshold(im, bw, 0, 255, Imgproc.THRESH_BINARY_INV | Imgproc.THRESH_OTSU);
Mat dist = new Mat(im.size(), CvType.CV_32F);
Imgproc.distanceTransform(bw, dist, Imgproc.CV_DIST_L2, Imgproc.CV_DIST_MASK_PRECISE);
Mat dibw32f = new Mat(im.size(), CvType.CV_32F);
final double SWTHRESH = 8.0; // stroke width threshold
Imgproc.threshold(dist, dibw32f, SWTHRESH/2.0, 255, Imgproc.THRESH_BINARY);
Mat dibw8u = new Mat(im.size(), CvType.CV_8U);
dibw32f.convertTo(dibw8u, CvType.CV_8U);
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(3, 3));
Mat cont = new Mat(im.size(), CvType.CV_8U);
Imgproc.morphologyEx(dibw8u, cont, Imgproc.MORPH_OPEN, kernel);
final double HTHRESH = im.rows() * 0.5;
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
List<Point> digits = new ArrayList<Point>();
Mat hierchy = new Mat();
Imgproc.findContours(cont, contours, hierchy, Imgproc.RETR_CCOMP, Imgproc.CHAIN_APPROX_SIMPLE, new Point(0, 0));
List<Mat>cleanedMatList = new ArrayList<Mat>();
int c = 0;
for (int i = 0; i >= hierchy.cols(); i++) {
Rect rect = Imgproc.boundingRect(contours.get(i));
if (rect.height > HTHRESH) {
Mat binary = new Mat();
Imgproc.rectangle(binary, new Point(rect.x, rect.y), new Point(rect.x + rect.width - 1, rect.y + rect.height - 1), new Scalar(0, 0, 255), 3);
cleanedMatList.add(c, binary);
c++;
}
}
List<MatOfInt> digitsHull = new ArrayList<MatOfInt>();
for(int i=0; i < contours.size(); i++){
digitsHull.add(new MatOfInt());
}
for(int i=0; i < contours.size(); i++){
Imgproc.convexHull(contours.get(i), digitsHull.get(i));
}
List<MatOfPoint> digitRegions = new ArrayList<MatOfPoint>();
for (int i = 0; i< digitRegions.size(); i++) {
MatOfPoint dr = digitRegions.get(i);
dr.push_back(digitsHull.get(i));
}
Mat digitsMask = new Mat(og.rows(),og.cols(), CvType.CV_8U);
Imgproc.drawContours(digitsMask, digitRegions, 0, new Scalar(255, 255, 255), -1);
Imgproc.morphologyEx(digitsMask, digitsMask, Imgproc.MORPH_DILATE, kernel);
Mat cleaned = new Mat(og.rows(), og.cols(), CvType.CV_8U);
dibw8u.copyTo(cleaned, digitsMask);
return HighGui.toBufferedImage(dibw8u);
}
public BufferedImage detectAndDisplay(BufferedImage img, CascadeClassifier faceCascade) {
Mat frameGray = new Mat();
BufferedImage imgout = null;
Mat image = ImagePreProcessing.bufferedImageToMat(img);
// -- Detect faces
MatOfRect faces = new MatOfRect();
faceCascade.detectMultiScale(image, faces);
List<Rect> listOfFaces = faces.toList();
for (Rect face : listOfFaces) {
Point center = new Point(face.x + face.width / 2, face.y + face.height / 2);
Imgproc.ellipse(image, center, new Size(face.width / 2, face.height / 2), 0, 0, 360,
new Scalar(255, 0, 255), 3);
Mat faceROI = image.submat(face);
imgout = ImagePreProcessing.Mat2BufferedImage(faceROI);
System.out.println("OpenCV: " +center);
}
return imgout;
}
that code I have..but I don't know where the code for setting crop output image.
I want to have the picture like original version with circle template..NOT to be crop
Can give me suggestion, please:)
input:
output:
In your code, you returned a cropped image of the original image, so if you want the original image, draw the circle and convert it to the BufferedImage and return.
for (Rect face : listOfFaces) {
Point center = new Point(face.x + face.width / 2, face.y + face.height / 2);
Imgproc.ellipse(image, center, new Size(face.width / 2, face.height / 2), 0, 0, 360,
new Scalar(255, 0, 255), 3);
// dot not crop!!!
/*Mat faceROI = image.submat(face);
imgout = ImagePreProcessing.Mat2BufferedImage(faceROI);*/
System.out.println("OpenCV: " +center);
imgout = ImagePreProcessing.Mat2BufferedImage(image);
}
To find the homography between 2 pictures I've used OpenCV 2.4.8, java version but got the following problem:
I can find more than 2 thousands matches but the findHomography function returns some negative values. The statement for the homography is the following:
Mat homography = Calib3d.findHomography(goodReferencePoints, goodScenePoints);
And as you can see in my terminal, the homography returns these negative values:
H= [0.0728467050846091, -1.778341899752422, 523.4269328629535;
0.05293440263461851, -1.283649810597391, 377.7784434651413;
0.0001384401936905583, -0.003397194330027168, 1]
The 1 at the end seems to me to be correct, but these is the only value in these matrix that it is correct :/
Any idea why? How can I get a better Matrix?
Thank you in advance
My code:
private void findCorners() {
Mat img_matches = new Mat();
List<DMatch> matchesList = matches.toList();
if (matchesList.size() < 4) {
// There are too few matches to find the homography.
System.err.println("There are too few matches to find the homography.");
return;
}
List<KeyPoint> object_keypoints_list = object_keypoints.toList();
List<KeyPoint> scene_keypoints_list = scene_keypoints.toList();
this.object_good_keypoints = new ArrayList<KeyPoint>();
this.scene_good_keypoints = new ArrayList<KeyPoint>();
// Calculate the max and min distances between keypoints.
double maxDist = 0.0;
double minDist = Double.MAX_VALUE;
for(DMatch match : matchesList) {
double dist = match.distance;
if (dist < minDist) {
minDist = dist;
}
if (dist > maxDist) {
maxDist = dist;
}
}
// The thresholds for minDist are chosen subjectively
// based on testing. The unit is not related to pixel
// distances; it is related to the number of failed tests
// for similarity between the matched descriptors.
if (minDist > 50.0) {
// The target is completely lost.
// Discard any previously found corners.
scene_corners.create(0, 0, scene_corners.type());
return;
} else if (minDist > 20.0) {
// The target is lost but maybe it is still close.
// Keep any previously found corners.
System.err.println("The target is lost but maybe it is still close. Keep any previously found corners.");
return;
}
// Identify "good" keypoints based on match distance.
ArrayList<Point> goodReferencePointsList = new ArrayList<Point>();
ArrayList<Point> goodScenePointsList = new ArrayList<Point>();
double maxGoodMatchDist = 1.75 * minDist;
for(DMatch match : matchesList) {
if (match.distance < maxGoodMatchDist) {
goodReferencePointsList.add(
object_keypoints_list.get(match.queryIdx).pt);
goodScenePointsList.add(
scene_keypoints_list.get(match.trainIdx).pt);
this.object_good_keypoints.add(object_keypoints_list.get(match.queryIdx));
this.scene_good_keypoints.add(scene_keypoints_list.get(match.trainIdx));
}
}
if (goodReferencePointsList.size() < 4 ||
goodScenePointsList.size() < 4) {
// There are too few good points to find the homography.
System.err.println("There are too few good points to find the homography.");
return;
}
System.out.println("Match found");
MatOfPoint2f goodReferencePoints = new MatOfPoint2f();
goodReferencePoints.fromList(goodReferencePointsList);
MatOfPoint2f goodScenePoints = new MatOfPoint2f();
goodScenePoints.fromList(goodScenePointsList);
System.out.println("goodReferencePoints size ="+goodReferencePoints.size());
System.out.println("goodScenePoints size ="+goodScenePoints.size());
Mat homography = Calib3d.findHomography(goodReferencePoints, goodScenePoints);
System.out.println("homography = "+homography.dump());
object_corners = new Mat(4, 1, CvType.CV_32FC2);
scene_corners = new Mat(4, 1, CvType.CV_32FC2);
object_corners.put(0, 0, new double[] { 0, 0 });
object_corners.put(1, 0, new double[] { object_image.cols(), 0 });
object_corners.put(2, 0, new double[] { object_image.cols(), object_image.rows() });
object_corners.put(3, 0, new double[] { 0, object_image.rows() });
Core.perspectiveTransform(object_corners, scene_corners, homography);
print_corners();
Point p0 = new Point(scene_corners.get(0, 0));
Point p1 = new Point(scene_corners.get(1, 0));
Point p2 = new Point(scene_corners.get(2, 0));
Point p3 = new Point(scene_corners.get(3, 0));
int offset = (int) new Point(object_corners.get(1, 0)).x;
System.out.println("Matches size = "+matches.size());
MatOfKeyPoint object_good_kp = new MatOfKeyPoint();
object_good_kp.fromList(this.object_good_keypoints);
MatOfKeyPoint scene_good_kp = new MatOfKeyPoint();
scene_good_kp.fromList(this.scene_good_keypoints);
System.out.println("object kps = "+this.object_keypoints.size());
System.out.println("object good kps = "+this.object_good_keypoints.size());
System.out.println("scene kps = "+this.scene_keypoints.size());
System.out.println("scene good kps = "+this.scene_good_keypoints.size());
Features2d.drawMatches(object_image, object_keypoints, scene_image, scene_keypoints, matches, img_matches, new Scalar(255, 0, 0),
new Scalar(0, 0, 255), new MatOfByte(), 2);
Core.line(img_matches, new Point(p0.x+offset, p0.y), new Point(p1.x+offset, p1.y), COLOR_GREEN, 4);
Core.line(img_matches, new Point(p1.x+offset, p1.y), new Point(p2.x+offset, p2.y), COLOR_GREEN, 4);
Core.line(img_matches, new Point(p2.x+offset, p2.y), new Point(p3.x+offset, p3.y), COLOR_GREEN, 4);
Core.line(img_matches, new Point(p3.x+offset, p3.y), new Point(p0.x+offset, p0.y), COLOR_GREEN, 4);
System.out.println(String.format("-- Writing result Mat in %s", pathResult));
Highgui.imwrite(pathResult, img_matches);
}
And here is the terminal output where we can see that the homography matrix has some negative values:
Match found
goodReferencePoints size =1x10
goodScenePoints size =1x10
homography = [0.0728467050846091, -1.778341899752422, 523.4269328629535;
0.05293440263461851, -1.283649810597391, 377.7784434651413;
0.0001384401936905583, -0.003397194330027168, 1]
-- Object-Point 0 [0,0]
-- Object-Point 1 [259,0]
-- Object-Point 2 [259,878]
-- Object-Point 3 [0,878]
-- Scene-Point 0 [523.43,377.78]
-- Scene-Point 1 [523.52,377.94]
-- Scene-Point 2 [523.45,377.81]
-- Scene-Point 3 [523.5,377.89]
Matches size = 1x2341
object kps = 1x2341
object good kps = 10
scene kps = 1x2576
scene good kps = 10
On the picture we can see that the matches are drawn but only one green point is there. It should be the contour in green, not just one point.
And the picture:
I have a project where I am trying to track a person as they move throughout a room. I am using an arduino, some servo motors and an xbox kinect for my camera.
I have a vision of allowing the project some training time where it can scan the room and make a database of images for the empty room. Then when a person enters the room the program can do a simple difference image to create a white blob for the person. Using this white blob I would be able to calculate the centre of mass for the person and compare it to the centre of the image frame in order to pass a command to the arduino telling it how far and in which direction to move the servo motors. I am using eclipse, writing in java and using opencv 2.4.6.
I am stuck on getting a clear white blob. I have already written my methods to calculate the distance from the centre of mass of the blob and the centre of the frame but without a clearly defined blob this is useless. I have been trying to get my program to work by taking a snap shot of the background of my room, changing the image to binary then subtracting it from a binary image of my room with me in it. This has not worked. Is my vision of training the system then comparing with these trained images valid or should I be going about a different way to detect an object?
I have tried implementing opticalflow() but it seems erratic and not extremely accurate.
Any information on the topic would be extremely helpful. I thank you in advance for reading my question.
-Trent
Edit: I have attached my code. The area in question is the training() and matdiff() methods.
package testingV1;
//OpenCv + OpenNI + Java Libraries
import java.awt.FlowLayout;
import java.util.ArrayList;
import java.util.List;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.io.*;
import java.nio.ByteBuffer;
import javax.imageio.ImageIO;
import javax.swing.*;
import org.opencv.core.*;
import org.opencv.imgproc.*;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.video.BackgroundSubtractorMOG;
import org.opencv.video.Video;
import org.opencv.highgui.*;
import org.opencv.*;
import org.OpenNI.*;
public class TestV1 {
static int imWidth = 640, imHeight = 480;
static ImageGenerator imageGen;
static Context context;
static int flag = CvType.CV_8UC3;
static int flag2 = CvType.CV_8UC1;
static Mat background;
public static void main(String[] args) throws GeneralException{
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
//We create a new "context" of the Kinect
context = new Context();
JFrame canvas = new JFrame("Optical Flow");
//need to create and add license to our "context"
License license = new License("PrimeSense", "0KOIk2JeIBYClPWVnMoRKn5cdY4=");
context.addLicense(license);
//defining the data we are taking from the kinect
MapOutputMode mapMode = null; //initialize it to null
mapMode = new MapOutputMode(imWidth, imHeight, 30); //create a 640x480 30fps feed definition
imageGen = ImageGenerator.create(context); //Rgb camera
imageGen.setMapOutputMode(mapMode); //change our feed to 640x480 30 fps
imageGen.setPixelFormat(PixelFormat.RGB24);///Pixel format, RGB 8-bit 3 channel
context.setGlobalMirror(true); //Mirrors our feed to make it more intuitive
BufferedImage rgbImage = new BufferedImage(imWidth, imHeight, BufferedImage.TYPE_INT_RGB);
BufferedImage prevImg = new BufferedImage(imWidth, imHeight, BufferedImage.TYPE_BYTE_GRAY);
BufferedImage currImg = new BufferedImage(imWidth, imHeight, BufferedImage.TYPE_BYTE_GRAY);
BufferedImage diffImg = new BufferedImage(imWidth, imHeight, BufferedImage.TYPE_BYTE_GRAY);
BufferedImage paintedImg = new BufferedImage(imWidth, imHeight, BufferedImage.TYPE_INT_RGB);
BufferedImage facesImg = new BufferedImage(imWidth, imHeight, BufferedImage.TYPE_INT_RGB);
Mat paintedMat = new Mat(imHeight, imWidth, flag);
Mat facesMat = new Mat(imHeight, imWidth, flag);
Mat currMat = new Mat(imHeight, imWidth, flag2);
Mat prevMat = new Mat(imHeight, imWidth, flag2);
Mat diffMat = new Mat(imHeight, imWidth, flag2);
Mat paintedMatg = new Mat(imHeight, imWidth, flag2);
ByteBuffer imageBB;
//First Frame
canvas.getContentPane().setLayout(new FlowLayout());
Icon video = new ImageIcon(rgbImage);
JLabel panel = new JLabel(video);
//Icon video2 = new ImageIcon(paintedImg);
//JLabel panel2 = new JLabel(video2);
//Icon video3 = new ImageIcon(facesImg);
//JLabel panel3 = new JLabel(video3);
Icon video4 = new ImageIcon(diffImg);
JLabel panel4 = new JLabel(video4);
canvas.getContentPane().add(panel);
//canvas.getContentPane().add(panel2);
//canvas.getContentPane().add(panel3);
canvas.getContentPane().add(panel4);
canvas.pack();
canvas.setVisible(true);
canvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CascadeClassifier faceDetectorAlg = new CascadeClassifier("C:/Users/Trent/Desktop/Capstone"
+ "/ComputerVisionCode/November16/testingV1/src/testingV1/haarcascade_frontalface_alt.xml");
boolean firstTime = true;
imageGen.startGenerating();
while(true){
context.waitOneUpdateAll(imageGen);
imageBB = imageGen.getImageMap().createByteBuffer(); //get KinectData
rgbImage = bufToImage(imageBB); //take data from kinect and put in BufferedImage
prevMat = currMat;
currMat = img2Mat(rgb2Gray(rgbImage));
if(firstTime){
training(rgbImage);
firstTime = false;
}
else{
diffMat = findDiff(currMat);
diffImg = mat2Img(diffMat);
}
//optical flow - inaccurate
//paintedMatg = opticalFlow(img2Mat(prevImg), img2Mat(currImg), 300, 0.01, 10);
//Imgproc.cvtColor(paintedMatg, paintedMat, Imgproc.COLOR_GRAY2RGB); //change from gray to color
//paintedImg = mat2Img(paintedMat);
//face detection - extremely resource intensive
//facesMat = faceDetector(img2Mat(rgbImage), faceDetectorAlg);
//facesImg = mat2Img(facesMat);
panel.setIcon(new ImageIcon(rgbImage));
//panel2.setIcon(new ImageIcon(paintedImg));
//panel3.setIcon(new ImageIcon(facesImg));
panel4.setIcon(new ImageIcon(diffImg));
canvas.repaint();
canvas.revalidate();
}
}
//establishes a background for better diff images
private static void training(BufferedImage in){
background = new Mat(imHeight, imWidth, flag2);
background = img2Mat(rgb2Gray(in));
System.out.println("Training Complete");
}
private static Mat findDiff(Mat in){
Mat output = new Mat(imHeight, imWidth, flag2);
Core.absdiff(background, in, output);
Imgproc.threshold(output, output, 20, 255, Imgproc.THRESH_BINARY);
return output;
}
//Face Detection
private static Mat faceDetector(Mat in, CascadeClassifier Alg){
Mat output = in;
MatOfRect faceDetections = new MatOfRect();
if(Alg.empty()){
System.out.println("didnt load");
return output;
}
Alg.detectMultiScale(in, faceDetections);
for(Rect rect : faceDetections.toArray()){
Core.rectangle(output, new Point(rect.x, rect.y),
new Point(rect.x + rect.width, rect.y + rect.height), new Scalar(0, 255, 0), 2);
}
return output;
}
//Returns an image with vectors painted to show movement.
private static Mat opticalFlow(Mat curr, Mat prev, int maxDetectionCount, double qualityLevel, double minDistance){
List<MatOfPoint2f> trackedPoints = new ArrayList<MatOfPoint2f>();
MatOfPoint initial = new MatOfPoint();
MatOfFloat err = new MatOfFloat();
MatOfByte status = new MatOfByte();
MatOfPoint2f initial2f = new MatOfPoint2f();
MatOfPoint2f next2f = new MatOfPoint2f();
double[] temp;
Point p1 = new Point();
Point p2 = new Point();
Mat output = new Mat(imHeight, imWidth, flag);
Scalar red = new Scalar(255, 0, 0);
//Finds Tracking points
if(trackedPoints.size() < 1){
Imgproc.goodFeaturesToTrack(curr, initial, maxDetectionCount, qualityLevel, minDistance);
initial.convertTo(initial2f, CvType.CV_32FC2);
trackedPoints.add(initial2f);
}
//catches first time frame
if(prev.empty())
curr.copyTo(prev);
//find points in current image
if(trackedPoints.get(0).total() > 0){
Video.calcOpticalFlowPyrLK(prev, curr, trackedPoints.get(0), next2f, status, err);
trackedPoints.add(next2f);
}
output = curr;
//draw red lines
for(int i = 0; i < trackedPoints.get(0).cols(); i++){
for(int j = 0; j < trackedPoints.get(0).rows(); j++){
temp = trackedPoints.get(0).get(j, i);
p1.set(temp);
temp = trackedPoints.get(1).get(j, i);
p2.set(temp);
Core.line(output, p1, p2, red);
}
}
return output;
}
//Returns a vector to indicate how the magnitude of movement.
private static double[] opticalFlowAnalysis(Mat curr, Mat prev, int maxDetectionCount, double qualityLevel, double minDistance){
List<MatOfPoint2f> trackedPoints = new ArrayList<MatOfPoint2f>();
MatOfPoint initial = new MatOfPoint();
MatOfFloat err = new MatOfFloat();
MatOfByte status = new MatOfByte();
MatOfPoint2f initial2f = new MatOfPoint2f();
MatOfPoint2f next2f = new MatOfPoint2f();
double[] total = new double[2];
total[0] = 0;
total[1] = 0;
double[] point1;
double[] point2;
double[] output = new double[2];
//Finds Tracking points
if(trackedPoints.size() < 1){
Imgproc.goodFeaturesToTrack(curr, initial, maxDetectionCount, qualityLevel, minDistance);
initial.convertTo(initial2f, CvType.CV_32FC2);
trackedPoints.add(initial2f);
}
//catches first time frame
if(prev.empty())
curr.copyTo(prev);
//find points in current image
if(trackedPoints.get(0).total() > 0){
Video.calcOpticalFlowPyrLK(prev, curr, trackedPoints.get(0), next2f, status, err);
trackedPoints.add(next2f);
}
//average the distance moved
// (-) signifies distance moved right and down
// (+) signifies distance moved left and up
for(int i = 0; i < trackedPoints.get(0).cols(); i++){
for(int j = 0; j < trackedPoints.get(0).rows(); j++){
point1 = trackedPoints.get(0).get(j, i);
point2 = trackedPoints.get(1).get(j, i);
total[0] += point1[0] - point2[0];
total[1] += point1[1] - point2[0];
}
}
output[0] = total[0] / trackedPoints.get(0).cols();
output[1] = total[1] / trackedPoints.get(0).rows();
return output;
}
private static Mat img2Mat(BufferedImage in){
Mat out;
byte[] data;
int r, g, b;
if(in.getType() == BufferedImage.TYPE_INT_RGB){
out = new Mat(imHeight, imWidth, flag);
data = new byte[imWidth * imHeight * (int)out.elemSize()];
int[] dataBuff = in.getRGB(0, 0, imWidth, imHeight, null, 0, imWidth);
for(int i = 0; i < dataBuff.length; i++){
data[i*3] = (byte) ((dataBuff[i] >> 16) & 0xFF);
data[i*3 + 1] = (byte) ((dataBuff[i] >> 8) & 0xFF);
data[i*3 + 2] = (byte) ((dataBuff[i] >> 0) & 0xFF);
}
}
else{
out = new Mat(imHeight, imWidth, flag2);
data = new byte[imWidth * imHeight * (int)out.elemSize()];
int[] dataBuff = in.getRGB(0, 0, imWidth, imHeight, null, 0, imWidth);
for(int i = 0; i < dataBuff.length; i++){
r = (byte) ((dataBuff[i] >> 16) & 0xFF);
g = (byte) ((dataBuff[i] >> 8) & 0xFF);
b = (byte) ((dataBuff[i] >> 0) & 0xFF);
data[i] = (byte)((0.21 * r) + (0.71 * g) + (0.07 * b)); //luminosity
}
}
out.put(0, 0, data);
return out;
}
private static BufferedImage mat2Img(Mat in){
BufferedImage out;
byte[] data = new byte[imWidth * imHeight * (int)in.elemSize()];
int type;
in.get(0, 0, data);
if(in.channels() == 1)
type = BufferedImage.TYPE_BYTE_GRAY;
else
type = BufferedImage.TYPE_3BYTE_BGR;
out = new BufferedImage(imWidth, imHeight, type);
out.getRaster().setDataElements(0, 0, imWidth, imHeight, data);
return out;
}
private static BufferedImage rgb2Gray(BufferedImage in){
BufferedImage out = new BufferedImage(imWidth, imHeight, BufferedImage.TYPE_BYTE_GRAY);
Mat color = new Mat(imHeight, imWidth, flag);
Mat gray = new Mat(imHeight, imWidth, flag);
color = img2Mat(in); //converting bufferedImage to Mat
Imgproc.cvtColor(color, gray, Imgproc.COLOR_RGB2GRAY); //change from color to grayscale
out = mat2Img(gray); //converting Mat to bufferedImage
return out;
}
//Converts bytebuffer to buffered image
private static BufferedImage bufToImage(ByteBuffer pixelsRGB){
int[] pixelInts = new int[imWidth * imHeight];
int rowStart = 0;
int bbIdx; //index to ByteBuffer
int i = 0; //index to pixels
int rowLen = imWidth * 3;
for (int row = 0; row < imHeight; row++){
bbIdx = rowStart;
for(int col = 0; col < imWidth; col++){
int pixR = pixelsRGB.get(bbIdx++);
int pixG = pixelsRGB.get(bbIdx++);
int pixB = pixelsRGB.get(bbIdx++);
pixelInts[i++] = 0xFF000000 | ((pixR & 0xFF) << 16) | ((pixG & 0xFF) << 8) | (pixB & 0xFF);
}
rowStart += rowLen; //Move to next row
}
BufferedImage im = new BufferedImage(imWidth, imHeight, BufferedImage.TYPE_INT_RGB);
im.setRGB(0, 0, imWidth, imHeight, pixelInts, 0, imWidth);
return im;
}
}
Answer to the question is bit late but may help for future references.
I think to learn about object detection you can look here and his code here (I learn from it to do my project). And then I made my project like this based on his object detection. Or you can look for a simple background subtraction here
I am making an OCR for my project and stuck on a point, Right now i am performing segmentation on the basis of contours its working fine with few images but there few more where it fails even when the image quality is good, I would appreciate if someone suggest me more accurate way, and if someone provide a code example, here is my current code.
public static void imageBinarization(IplImage src, IplImage dst){
IplImage r, g, b, s;
r = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
g = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
b = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
cvSplit(src, r, g, b, null);
s = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
cvAddWeighted(r, 1./3., g, 1./3., 0.0, s);
cvAddWeighted(s, 2./3., b, 1./3., 0.0, s);
cvThreshold(s, dst, 100, 100, CV_THRESH_BINARY_INV);
cvReleaseImage(r);
cvReleaseImage(g);
cvReleaseImage(b);
cvReleaseImage(s);
}
public static void imageSegmentation(String sourcePath, String targetPath){
cvConvert(t0, mat0);
cvConvert(t8, mat8);
cvConvert(t9, mat9);
IplImage image = cvLoadImage(sourcePath);
IplImage grayImage = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
//cvSmooth(image, image, CV_BLUR_NO_SCALE, 2);
//cvSmooth(image, image, CV_BLUR, 9, 9, 2, 2);
//cvSmooth(image, image, CV_GAUSSIAN, 3);
imageBinarization(image, grayImage);
CvMemStorage mem;
CvSeq contours = new CvSeq();
CvSeq ptr = new CvSeq();
mem = cvCreateMemStorage(0);
CvRect rect = null;
int px1,px2, py1, py2;
CvScalar blue = CV_RGB(0, 0, 250);
int n = 0; int i = 0;
cvFindContours(grayImage, mem, contours, sizeof(CvContour.class) , CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
Random rand = new Random();
for (ptr = contours; ptr != null; ptr = ptr.h_next()) {
Color randomColor = new Color(rand.nextFloat(), rand.nextFloat(), rand.nextFloat());
CvScalar color = CV_RGB( randomColor.getRed(), randomColor.getGreen(), randomColor.getBlue());
rect = cvBoundingRect(ptr, n);//new CvRect(cvGetSeqElem(c, c.total()));
px1 = rect.x(); py1 = rect.y(); px2 = (rect.x() + rect.width()); py2 = (rect.y() + rect.height());
cvRectangle(image, cvPoint(px1, py1), cvPoint(px2, py2), blue, 1, CV_AA, 0);
//----
xbox = rect.x(); ybox = rect.y(); wbox = rect.width(); hbox = rect.height();
img = cvCreateImage(cvSize(wbox, hbox), image.depth(), image.nChannels());
cvSetImageROI(image, cvRect(xbox, ybox, wbox, hbox));
cvCopy(image, img);
cvResetImageROI(image);
//cvSaveImage(targetPath+i+".jpg", img);
i++;
//---
//cvDrawContours(image, ptr, color, CV_RGB(0,0,0), -1, CV_FILLED, 8, cvPoint(0,0));
}
cvSaveImage(targetPath+"mat.jpg", image);
}
Try to use some Global Thresholding algorithm such as Otsu. But JavaCV haven't implemented that. So try to find the Otsu threshold level using histogram processing and apply that value to
cvThreshold(s, dst, 100, 100, CV_THRESH_BINARY_INV);