I am using OpenCV's sample code to detect face with android device. I want to save only detected face area to sd card. I am trying to convert mat to Bitmap and save it. But my problem is it saves whole image rather than just Face. here's my method to convert mat to bitmap
Bitmap bitmap = Bitmap.createBitmap(mGray.cols(), mGray.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mGray, bitmap);
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/saved_images");
myDir.mkdirs();
Random generator = new Random();
int n = 10000;
n = generator.nextInt(n);
String fname = "Image-"+ n +".jpg";
File file = new File (myDir, fname);
if (file.exists ()) file.delete ();
try {
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
I am a beginner with Opencv. Please help. Thank you in advance
The problem is, you are never trying to get the face pixels. After you detect face, I suggest you to do something such as:
Mat mFaceMatrix = mRgba.submat(facesArray.y, facesArray.y + facesArray.heigth, facesArray.x, facesArray.x + facesArray.width);
Now passing this matrix to createBitmap function should do the trick.
Bitmap bitmap = Bitmap.createBitmap(mFaceMatrix.cols(), mFaceMatrix.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mFaceMatrix, bitmap);
Your code looks fine. I think the problem is with your matrix mGray. It seems that mGray contains the whole image pixels and you are creating bitmap using it. Therefore, my suggestion would be to first check your mGray matrix and take face region and copy the pixels to another matrix and then create bitmap with that new matrix that contains just the face.
Hope it helps.
Let assume that there is only one face. We can crop the result of the face detection and save it as described in this python script:
import cv2
import sys
cascPath = sys.argv[1]
faceCascade = cv2.CascadeClassifier(cascPath)
video_capture = cv2.VideoCapture(0)
while True:
# Capture frame-by-frame
ret, frame = video_capture.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = faceCascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30),
flags=cv2.cv.CV_HAAR_SCALE_IMAGE
)
# Draw a rectangle around the faces
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
# Display the resulting frame
cv2.imshow('Video', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
if cv2.waitKey(1) & 0xFF == ord('c'):
crop = frame[y: y + h, x: x + w]
cv2.imwrite("face.jpg", crop)
# When everything is done, release the capture
video_capture.release()
cv2.destroyAllWindows()
Related
I need to create .jpeg/.png file on my Android application programmatically. I have simple image (black background), and it need to write some text on it programmatically. How can I do it? Is it possible?
It's definately possible.
To write text on an image you have to load the image in to a Bitmap object. Then draw on that bitmap with the Canvas and Paint functions. When you're done drawing you simply output the Bitmap to a file.
If you're just using a black background, it's probably better for you to simply create a blank bitmap on a canvas, fill it black, draw text and then dump to a Bitmap.
I used this tutorial to learn the basics of the canvas and paint.
This is the code that you'll be looking for to turn the canvas in to an image file:
OutputStream os = null;
try {
File file = new File(dir, "image" + System.currentTimeMillis() + ".png");
os = new FileOutputStream(file);
finalBMP.compress(CompressFormat.PNG, 100, os);
finalBMP.recycle(); // this is very important. make sure you always recycle your bitmap when you're done with it.
screenGrabFilePath = file.getPath();
} catch(IOException e) {
finalBMP.recycle(); // this is very important. make sure you always recycle your bitmap when you're done with it.
Log.e("combineImages", "problem combining images", e);
}
Yes, see here
Bitmap b = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
You can also use awt's Graphics2D with this compatibility project
Using Graphics2d you can create a PNG image as well:
public class Imagetest {
public static void main(String[] args) throws IOException {
File path = new File("image/base/path");
BufferedImage img = new BufferedImage(100, 100,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(Color.YELLOW);
g2d.drawLine(0, 0, 50, 50);
g2d.setColor(Color.BLACK);
g2d.drawLine(50, 50, 0, 100);
g2d.setColor(Color.RED);
g2d.drawLine(50, 50, 100, 0);
g2d.setColor(Color.GREEN);
g2d.drawLine(50, 50, 100, 100);
ImageIO.write(img, "PNG", new File(path, "1.png"));
}
}
I'm quite new to OpenCV programming, and I'm developing an app that works like this:
Take photo of a shelf from camera
Analyze it with openCV to detect all the rectangles in the photo (i.e. want to find all the products stored on the shelf)
crop all the rectangle elements found.
My problem is that the detection phase works not so well.
The code used to analyze the taken photo:
Bitmap originalPhoto;
byte[] bytes = photo.getByteArray("bitmap");
originalPhoto = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
Mat imgMat=new Mat();
Utils.bitmapToMat(originalPhoto,imgMat);
Mat imgSource=imgMat.clone();
Imgproc.cvtColor( imgMat, imgMat, Imgproc.COLOR_BGR2GRAY);
Bitmap grayscale=Bitmap.createBitmap(imgMat.cols(),imgMat.rows(),Bitmap.Config.ARGB_8888);
Utils.matToBitmap(imgMat,grayscale);
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/saved_images");
Imgproc.Canny(imgMat,imgMat,0,255);
Bitmap canny=Bitmap.createBitmap(imgMat.cols(),imgMat.rows(),Bitmap.Config.ARGB_8888);
Utils.matToBitmap(imgMat,canny);
Imgproc.GaussianBlur(imgMat, imgMat, new org.opencv.core.Size(1, 1), 2, 2);
Bitmap blur=Bitmap.createBitmap(imgMat.cols(),imgMat.rows(),Bitmap.Config.ARGB_8888);
Utils.matToBitmap(imgMat,blur);
//find the contours
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
Imgproc.findContours(imgMat, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
MatOfPoint temp_contour = contours.get(0); //the largest is at the index 0 for starting point
for (int idx = 0; idx < contours.size(); idx++) {
temp_contour = contours.get(idx);
//check if this contour is a square
MatOfPoint2f new_mat = new MatOfPoint2f( temp_contour.toArray() );
int contourSize = (int)temp_contour.total();
MatOfPoint2f approxCurve_temp = new MatOfPoint2f();
Imgproc.approxPolyDP(new_mat, approxCurve_temp, contourSize*0.05, true);
if (approxCurve_temp.total() == 4) {
MatOfPoint points = new MatOfPoint( approxCurve_temp.toArray() );
Rect rect = Imgproc.boundingRect(points);
Core.rectangle(imgSource, new Point(rect.x,rect.y), new Point(rect.x+rect.width,rect.y+rect.height), new Scalar(255, 0, 0, 255), 3);
}
}
Bitmap analyzed=Bitmap.createBitmap(imgSource.cols(),imgSource.rows(),Bitmap.Config.ARGB_8888);
Utils.matToBitmap(imgSource,analyzed);
if(!myDir.exists()) myDir.mkdirs();
fname = "ImageAnalyzed.png";
file = new File (myDir, fname);
if (file.exists ()) file.delete ();
try {
FileOutputStream out = new FileOutputStream(file);
analyzed.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
The result photo is not correctly analyzed, it returns to me a photo like this:
Has anyone an idea on how to solve it?
Thanks in advance,
Fabio
edit
I found that using ImgProc.APPROX_CHAIN_NONE instead of ImgProc.APPROX_CHAIN_SIMPLE gives me much better results... Now I have to tune canny thresholds to give the program independency wrt the type of image I analyze. I think that using mean or median values of the image will give me better results as well.
I am trying to plot the R channel of an image as a heatmap using the following code:
// Read image as a Mat of 32bit float
Mat imgMain = new Mat(n_height, n_width, CvType.CV_32FC4);
image = BitmapFactory.decodeFile("img.jpg");
Utils.bitmapToMat(image, imgMain);
imgMain.convertTo(imgMain, CvType.CV_32FC4);
// Extract R channel
Mat imgChR = new Mat(n_height, n_width, CvType.CV_32FC1);
extractChannel(imgMain, imgChR, 0);
// imgChR processed with floating point arithmetic
// Convert to HeatMap
normalize(imgChR, imgChR, 0, 1, NORM_MINMAX);
Mat heatOut = new Mat(n_height, n_width, CvType.CV_8UC4);
applyColorMap(imgChR, heatOut, COLORMAP_JET);
// Save as Image
pimage = Bitmap.createBitmap(n_width, n_height, Bitmap.Config.ARGB_8888);
Utils.matToBitmap(heatOut, pimage);
File f = new File("heat.jpeg");
FileOutputStream fos = new FileOutputStream(f);
pimage.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
For averaging multiple copies of the image, I am converting the matrix from integers to floats. (The averaging process is abstracted in the following code but please note that the type has to be converted to a 32bit float)
Using the following code, I simply get a black image.
Is this the right approach for plotting a heatmap of a single channel matrix?
If not, is there any other function or approach that can be used?
(When I check the type of heatOut the function returns a 0 as a integer representation of the Mat type.)
Presently I am designing an application based on photo editing. While doing this i encountered with a problem i.e.
I have gone through a tutorial "how to apply RGB color filter for an image" from this link and this tutorial is very helpful and nice.
But the problem is after applying RGB color filter to the image i need to save the changed image in sd card.
I have googled a lot for this but didn't found exact thing.
Many of them sugested to use paint() But im not getting how to use that.
So exactly my problem is "After Applying RBG Coloration to image I need to save that image in SD Card, But I do not found the how to do it" ?
How to Save an Android ImageView to SD Card
You have an ImageView which you've modified via various lighting effects and color filters and now you wish to save the result to the SD card as as a .jpg or .png format image.
Here's how:
Load Bitmap image from View.
Save Bitmap image to SD card.
Example:
Don't forget to test for Exceptions and add the necessary permissions to your manifest!
ImageView imageView = <View to save to SD card>;
Bitmap bitmap = loadBitmapFromView(imageView);
final String pathTxt = Environment.getExternalStorageDirectory();
File storagePath = new File(pathTxt);
File file = new File(storagePath, "filename.jpg");
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
out.flush();
out.close();
private Bitmap loadBitmapFromView(View v) {
final int w = v.getWidth();
final int h = v.getHeight();
final Bitmap b = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
final Canvas c = new Canvas(b);
//v.layout(0, 0, w, h);
v.layout(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
v.draw(c);
return b;
}
Theree are two methods for this...
1.after applying RGB values save those values in a variables and apply that values to the image selected.
2.after applying RGB values take the image from image view and save it
I changed my question a bit.
EDIT:
// make textures from text
public static void createTextureFromText(GL10 gl, String text, String texName) {
Paint p = new Paint();
p.setColor(Color.GREEN);
p.setTextSize(32 * getResources().getDisplayMetrics().density);
// get width and height the text takes (in px)
int width = (int) p.measureText(text);
int height = (int) p.descent();
// Create an empty, mutable bitmap based on textsize
Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
// get a canvas to paint over the bitmap
Canvas canvas = new Canvas(bmp);
bmp.eraseColor(Color.CYAN); //Cyan for debugging purposes
//draw the text
canvas.drawText(text, 0, 0, p);
// save image - for debugging purposes
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG, 40, bytes);
// create a new file name "test.jpg" in sdcard
File f = new File(Environment.getExternalStorageDirectory() + File.separator + "test.jpg");
try {
f.createNewFile();
// write the bytes in file
FileOutputStream fo = new FileOutputStream(f);
fo.write(bytes.toByteArray());
fo.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
.... make texture
}
I now have this code in use for creating textures from given text (this is just partially).
But I found the fault lies somewhere in the Bitmap creation. I now save the Bitmap on the sd-card, to see how it turns out and found I get a ALL Cyan bitmap (672B, 164x7 are the dimensions).
Does Anyone see why it doesn't create an Bitmap with text on it? What can I be doing wrong?
You'll be a hero if you could help me :)
Firstly, your text height calculation is wrong. The 'descent' measurement is just the portion of text below the baseline (i.e. the tails of 'g' and 'q' etc). The correct height is ascent+descent, except that since ascent is negative you want:
int height = (int) (p.descent() + -p.ascent());
Secondly, when you drawText() the y coordinate you give it is where the baseline goes, it is not the top or bottom edge. So if you want to fill a bitmap that's just big enough to hold the text, your y coordinate should also be -p.ascent().