I am using android "opencv samples - face detection" to detect the face. It is working good. Now I want to include "eye detection" with "face detection". Is it possible? if yes can anyone give me some samples to detect the eye. I have searched over the internet. But I didn't get any samples.
You can detect the eyes using this code...(on number of faces)
//code...
public void setFace() {
FaceDetector fd;
mFaceBitmap = mBitmap.copy(Bitmap.Config.RGB_565, true);
mFaceWidth = mFaceBitmap.getWidth();
mFaceHeight = mFaceBitmap.getHeight();
FaceDetector.Face [] faces = new FaceDetector.Face[MAX_FACES];
PointF eyescenter = new PointF();
float eyesdist = 0.0f;
int [] fpx = null;
int [] fpy = null;
try {
Log.e("setFace(): ", "try");
fd = new FaceDetector(mFaceWidth, mFaceHeight, MAX_FACES);
count = fd.findFaces(mFaceBitmap, faces);
} catch (Exception e) {
return;
}
// check if we detect any faces
if (count > 0) {
fpx = new int[count * 1];
fpy = new int[count * 1];
for (int i = 0; i < count; i++) {
try {
Log.e("setFace(): ", "loop");
faces[i].getMidPoint(eyescenter);
eyesdist = faces[i].eyesDistance();
// set up left eye location
fpx[1 * i] = (int)(eyescenter.x - eyesdist / 2);
fpy[1 * i] = (int)eyescenter.y;
// set up right eye location
fpx[1 * i + 1] = (int)(eyescenter.x + eyesdist / 2);
fpy[1 * i + 1] = (int)eyescenter.y;
} catch (Exception e) {
}
}
MainActivity.clicked = true;
}
}
I think that is possible. You need to load another cascade (nested cascade) and use the detectMultiScale in the ROI detected by the face cascade. Take a look at the facedetect.cpp example in the c samples.
Yes, you can do this. There is both a generic eye detector, and specific left/right eye detectors available.
You can use the same Haar cascade code you used for faces, just substituting the eye detectors.
In practice, I've found that it's better to try both - start with the generic eye detector, then if nothing is found in a reasonable location, move on to the left and right eye detectors.
You can go through this code
public FdView(Context context) {
super(context);
this.context = context;
try {
InputStream is = context.getResources().openRawResource(
R.raw.lbpcascade_frontalface);
File cascadeDir = context.getDir("cascade", Context.MODE_PRIVATE);
mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
FileOutputStream os = new FileOutputStream(mCascadeFile);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1) {
os.write(buffer, 0, bytesRead);
}
is.close();
os.close();
// ------------------------- load left eye classificator//
// -----------------------------------
InputStream iser = context.getResources().openRawResource(
R.raw.haarcascade_lefteye_2splits);
File cascadeDirER = context.getDir("cascadeER",
Context.MODE_PRIVATE);
File cascadeFileER = new File(cascadeDirER,
"haarcascade_eye_right.xml");
FileOutputStream oser = new FileOutputStream(cascadeFileER);
byte[] bufferER = new byte[4096];
int bytesReadER;
while ((bytesReadER = iser.read(bufferER)) != -1) {
oser.write(bufferER, 0, bytesReadER);
}
iser.close();
oser.close();
// ----------------------------------------------------------------------------------------------------
// --------------------------------- load right eye classificator//
// ------------------------------------
InputStream isel = context.getResources().openRawResource(
R.raw.haarcascade_lefteye_2splits);
File cascadeDirEL = context.getDir("cascadeEL",
Context.MODE_PRIVATE);
File cascadeFileEL = new File(cascadeDirEL,
"haarcascade_eye_left.xml");
FileOutputStream osel = new FileOutputStream(cascadeFileEL);
byte[] bufferEL = new byte[4096];
int bytesReadEL;
while ((bytesReadEL = isel.read(bufferEL)) != -1) {
osel.write(bufferEL, 0, bytesReadEL);
}
isel.close();
osel.close();
// ------------------------------------------------------------------------------------------------------
mJavaDetector = new CascadeClassifier(
mCascadeFile.getAbsolutePath());
mCascadeER = new CascadeClassifier(cascadeFileER.getAbsolutePath());
mCascadeEL = new CascadeClassifier(cascadeFileER.getAbsolutePath());
if (mJavaDetector.empty() || mCascadeER.empty()
|| mCascadeEL.empty()) {
Log.e(TAG, "Failed to load cascade classifier");
mJavaDetector = null;
mCascadeER = null;
mCascadeEL = null;
} else
Log.i(TAG,
"Loaded cascade classifier from "
+ mCascadeFile.getAbsolutePath());
mNativeDetector = new DetectionBasedTracker(
mCascadeFile.getAbsolutePath(), 0);
cascadeDir.delete();
cascadeFileER.delete();
cascadeDirER.delete();
cascadeFileEL.delete();
cascadeDirEL.delete();
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "Failed to load cascade. Exception thrown: " + e);
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
synchronized (this) {
// initialize Mats before usage
mGray = new Mat();
mRgba = new Mat();
}
super.surfaceCreated(holder);
}
#Override
protected Bitmap processFrame(VideoCapture capture) {
capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
capture.retrieve(mGray, Highgui.CV_CAP_ANDROID_GREY_FRAME);
if (mAbsoluteFaceSize == 0) {
int height = mGray.rows();
if (Math.round(height * mRelativeFaceSize) > 0)
{
mAbsoluteFaceSize = Math.round(height * mRelativeFaceSize);
}
mNativeDetector.setMinFaceSize(mAbsoluteFaceSize);
}
MatOfRect faces = new MatOfRect();
if (mDetectorType == JAVA_DETECTOR) {
if (mJavaDetector != null)
mJavaDetector.detectMultiScale(mGray, faces, 1.1, 2, 2,
new Size(mAbsoluteFaceSize, mAbsoluteFaceSize),
new Size());
/*
* if (mZoomCorner == null || mZoomWindow == null)
* CreateAuxiliaryMats();
*/
Rect[] facesArray = faces.toArray();
for (int i = 0; i < facesArray.length; i++) {
Rect r = facesArray[i];
Core.rectangle(mGray, r.tl(), r.br(),new Scalar(255, 0, 255, 0), 3);
Core.rectangle(mRgba, r.tl(), r.br(),new Scalar(46, 139, 87, 5), 3);
//eyearea = new Rect(r.x + r.width / 8,(int) (r.y + (r.height / 4.5)), r.width - 10 * r.width/ 8, (int) (r.height / 3.0));
// Core.rectangle(mRgba, eyearea.tl(), eyearea.br(), new Scalar(255, 0, 0, 255), 3);
Rect eyearea_right = new Rect(r.x + r.width / 16,
(int) (r.y + (r.height / 4.5)),
(r.width - 2 * r.width / 16) / 2,(int) (r.height / 3.0));
Rect eyearea_left = new Rect(r.x + r.width / 16+ (r.width - 2 * r.width / 16) / 2,(int) (r.y + (r.height / 4.5)),(r.width - 2 * r.width / 16) / 2,(int) (r.height / 3.0));
// outer recTangles
//Core.rectangle(mRgba, eyearea_left.tl(), eyearea_left.br(),new Scalar(0, 255, 255, 255), 3);
//Core.rectangle(mRgba, eyearea_right.tl(), eyearea_right.br(),new Scalar(0, 255, 255, 255), 3);
teplateR = get_template(mCascadeER, eyearea_right, 3);
teplateL = get_template(mCascadeEL, eyearea_left, 3);
learn_frames++;
/*
* match_value = match_eye(eyearea_right, teplateR,
* FdActivity.method);
*
* match_value = match_eye(eyearea_left, teplateL,
* FdActivity.method); ; }
*/
/************************************************************************************************/
/*
* Imgproc.resize(mRgba.submat(eyearea_left), mZoomWindow2,
* mZoomWindow2.size());
* Imgproc.resize(mRgba.submat(eyearea_right), mZoomWindow,
* mZoomWindow.size());
*/
}
} else if (mDetectorType == NATIVE_DETECTOR) {
if (mNativeDetector != null)
mNativeDetector.detect(mGray, faces);
} else {
Log.e(TAG, "Detection method is not selected!");
}
Rect[] facesArray = faces.toArray();
for (int i = 0; i < facesArray.length; i++)
Core.rectangle(mRgba, facesArray[i].tl(), facesArray[i].br(),
FACE_RECT_COLOR, 3);
Bitmap bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(),
Bitmap.Config.ARGB_8888);
try {
Utils.matToBitmap(mRgba, bmp);
} catch (Exception e) {
Log.e(TAG,
"Utils.matToBitmap() throws an exception: "
+ e.getMessage());
bmp.recycle();
bmp = null;
}
return bmp;
}
Hope this will help you.
Related
Edited:
If anyone one can suggest any link or post, I will be very grateful. I am trying to find solution from two days and i can't find any.Thank you in advance.
I am trying to put one object(image) on particular location of screen Using openCv in android.
I do have Points like this "{680.0, 488.0}" which is having (x,y) coordinate,
So how can I find particular location in my screen for putting object ?
Below is my code where i am getting Point:
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
mGray = inputFrame.gray();
iThreshold = minTresholdSeekbar.getProgress();
//Imgproc.blur(mRgba, mRgba, new Size(5,5));
Imgproc.GaussianBlur(mRgba, mRgba, new org.opencv.core.Size(3, 3), 1, 1);
//Imgproc.medianBlur(mRgba, mRgba, 3);
if (!mIsColorSelected) return mRgba;
List<MatOfPoint> contours = mDetector.getContours();
mDetector.process(mRgba);
Log.d(TAG, "Contours count: " + contours.size());
if (contours.size() <= 0) {
return mRgba;
}
RotatedRect rect = Imgproc.minAreaRect(new MatOfPoint2f(contours.get(0).toArray()));
double boundWidth = rect.size.width;
double boundHeight = rect.size.height;
int boundPos = 0;
for (int i = 1; i < contours.size(); i++) {
rect = Imgproc.minAreaRect(new MatOfPoint2f(contours.get(i).toArray()));
if (rect.size.width * rect.size.height > boundWidth * boundHeight) {
boundWidth = rect.size.width;
boundHeight = rect.size.height;
boundPos = i;
}
}
Rect boundRect = Imgproc.boundingRect(new MatOfPoint(contours.get(boundPos).toArray()));
//Core/Imgproc.rectangle( mRgba, boundRect.tl(), boundRect.br(), CONTOUR_COLOR_WHITE, 2, 8, 0 );
Log.d(TAG,
" Row start [" +
(int) boundRect.tl().y + "] row end [" +
(int) boundRect.br().y + "] Col start [" +
(int) boundRect.tl().x + "] Col end [" +
(int) boundRect.br().x + "]");
int rectHeightThresh = 0;
double a = boundRect.br().y - boundRect.tl().y;
a = a * 0.7;
a = boundRect.tl().y + a;
Log.d(TAG,
" A [" + a + "] br y - tl y = [" + (boundRect.br().y - boundRect.tl().y) + "]");
//Core.rectangle( mRgba, boundRect.tl(), boundRect.br(), CONTOUR_COLOR, 2, 8, 0 );
//Core/Imgproc.rectangle( mRgba, boundRect.tl(), new Point(boundRect.br().x, a), CONTOUR_COLOR, 2, 8, 0 );
MatOfPoint2f pointMat = new MatOfPoint2f();
Imgproc.approxPolyDP(new MatOfPoint2f(contours.get(boundPos).toArray()), pointMat, 3, true);
contours.set(boundPos, new MatOfPoint(pointMat.toArray()));
MatOfInt hull = new MatOfInt();
MatOfInt4 convexDefect = new MatOfInt4();
Imgproc.convexHull(new MatOfPoint(contours.get(boundPos).toArray()), hull);
if (hull.toArray().length < 3) return mRgba;
Imgproc.convexityDefects(new MatOfPoint(contours.get(boundPos).toArray()), hull, convexDefect);
List<MatOfPoint> hullPoints = new LinkedList<MatOfPoint>();
List<Point> listPo = new LinkedList<Point>();
for (int j = 0; j < hull.toList().size(); j++) {
listPo.add(contours.get(boundPos).toList().get(hull.toList().get(j)));
}
MatOfPoint e = new MatOfPoint();
e.fromList(listPo);
hullPoints.add(e);
List<MatOfPoint> defectPoints = new LinkedList<MatOfPoint>();
List<Point> listPoDefect = new LinkedList<Point>();
for (int j = 0; j < convexDefect.toList().size(); j = j + 4) {
Point farPoint = contours.get(boundPos).toList().get(convexDefect.toList().get(j + 2));
Integer depth = convexDefect.toList().get(j + 3);
if (depth > iThreshold && farPoint.y < a) {
listPoDefect.add(contours.get(boundPos).toList().get(convexDefect.toList().get(j + 2)));
}
Log.d(TAG, "defects [" + j + "] " + convexDefect.toList().get(j + 3));
}
MatOfPoint e2 = new MatOfPoint();
e2.fromList(listPo);
defectPoints.add(e2);
Log.d(TAG, "hull: " + hull.toList());
Log.d(TAG, "defects: " + convexDefect.toList());
Imgproc.drawContours(mRgba, hullPoints, -1, CONTOUR_COLOR, 3);
int defectsTotal = (int) convexDefect.total();
Log.d(TAG, "Defect total " + defectsTotal);
this.numberOfFingers = listPoDefect.size();
if (this.numberOfFingers > 5) {
this.numberOfFingers = 5;
} /*else if (this.numberOfFingers == 1) {
this.numberOfFingers = 0;
}
*/
mHandler.post(mUpdateFingerCountResults);
runOnUiThread(new Runnable() {
#Override
public void run() {
ring.setVisibility(View.VISIBLE);
/*LinearLayout.LayoutParams parms = new LinearLayout.LayoutParams(10,10);
ring.setLayoutParams(parms);*/
}
});
for (Point p : listPoDefect) {
Log.e("Points", p.toString());
// Imgproc.circle(mRgba, p, 6, new Scalar(255,0,255));
}
return mRgba;
}
Below is the method which i have used to save image and display. Now i need to put ring on one of captured hand fingers.
private void saveImage() {
if (MainActivity.listPoDefect.size() >= 5) {
mIsColorSelected = false;
if (listPoDefect.size() != 0) {
for (Point p :listPoDefect) {
Log.d(TAG, "before sorting X =" + String.valueOf(p.x) + " Y = " + String.valueOf(p.y));
}
Collections.sort(listPoDefect, new Comparator<Point>() {
public int compare(Point o1, Point o2) {
return Double.compare(o1.x, o2.x);
}
});
Log.d(TAG, "After Sorting ");
for (Point p : listPoDefect) {
Log.d(TAG, "after sorting X =" + String.valueOf(p.x) + " Y = " + String.valueOf(p.y));
}
}
mIsColorSelected = false;
Bitmap bitmap5 = Bitmap.createBitmap(mRgbaWithoutLine.cols(), mRgbaWithoutLine.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mRgbaWithoutLine, bitmap5);
bitmap = bitmap5;
//Create a new image bitmap and attach a brand new canvas to it
Bitmap tempBitmap = Bitmap.createBitmap(bitmap5.getWidth(), bitmap5.getHeight(), Bitmap.Config.RGB_565);
Canvas tempCanvas = new Canvas(tempBitmap);
//Draw the image bitmap into the cavas
tempCanvas.drawBitmap(bitmap5, 0, 0, null);
double scaledWidth = bitmap5.getWidth();
double scaledHeight = bitmap5.getHeight();
double xScaleFactor = scaledWidth / bitmap5.getWidth();
double yScaleFactor = scaledHeight / bitmap5.getHeight();
Paint myRectPaint = new Paint();
myRectPaint.setStyle(Paint.Style.STROKE);
myRectPaint.setColor(Color.RED);
myRectPaint.setStrokeWidth(5);
myRectPaint.setAntiAlias(true);
//this is zeroth position manipulation
double differenceX= listPoDefect.get(2).x-listPoDefect.get(1).x;
double differenceY= listPoDefect.get(2).y-listPoDefect.get(1).y;
double zeroPostionX=listPoDefect.get(1).x-differenceX;
double zeroPostionY=listPoDefect.get(1).y-differenceY;
Point pointZeroths=listPoDefect.get(0);
Point pointNew=new Point(zeroPostionX,zeroPostionY);
listPoDefect.remove(0);
listPoDefect.add(0,pointNew);
double thirdPostionX=listPoDefect.get(2).x+differenceX;
double thirdPostionY=listPoDefect.get(2).y+differenceY;
Point thirdpointNew=new Point(thirdPostionX,thirdPostionY);
listPoDefect.remove(3);
listPoDefect.add(3,thirdpointNew);
// Point pointNewThird=new Point(pointthird.x+differenc,pointthird.y);
// HomeActivity.listPoDefect.remove(3);
// HomeActivity.listPoDefect.add(3,pointNewThird);
Paint paint_text = new Paint();
paint_text.setColor(Color.WHITE);
paint_text.setStyle(Paint.Style.FILL);
paint_text.setTextSize(30);
for (int row = 0; row < 4; row++) { // draw 2 rows
Point point1 = null;
point1 = listPoDefect.get(row);
android.graphics.Point canvas_point1 = new android.graphics.Point((int) ((point1.x * xScaleFactor)), (int) ((point1.y * yScaleFactor)));
Log.d(TAG, "after sorting canvas_point1 ="+"Raw ="+row +" " + String.valueOf(canvas_point1.x) + " Y = " + String.valueOf(canvas_point1.y));
Log.d(TAG, "====================================================================================================");
if(pointFListGraphies.size()!=4)
{
pointFListGraphies.add(new PointF(canvas_point1));
}
// tempCanvas.drawRect(canvas_point1.x, canvas_point1.y, canvas_point1.x + 130, canvas_point1.y + 50, myRectPaint);
// tempCanvas.drawText(String.valueOf(row+"-"+canvas_point1.x), canvas_point1.x, canvas_point1.y, paint_text);
}
Log.d(TAG, "====================================================================================================");
for (int row = 0; row < pointFListGraphies.size(); row++) { // draw 2 rows
PointF point1 = null;
point1 = pointFListGraphies.get(row);
Log.d(TAG, "=========pointF X="+point1.x +"poninF Y =" +point1.y);
}
tempbitmap = tempBitmap;
handImage.setVisibility(View.VISIBLE);
handImage.setImageBitmap(tempbitmap);
/* Bitmap src = BitmapFactory.decodeResource(getResources(), R.drawable.ring);
tempCanvas.drawBitmap();*/
onCameraViewStopped();
//finish();
}
else {
}
}
Can anyone help me?
Thanks in advance.
OpenCV has a number of functions for writing on an image, which is usually what you are displaying on the screen.
FOr example the function to write text a particular location is
void cv::putText ( InputOutputArray img,
const String & text,
Point org,
int fontFace,
double fontScale,
Scalar color,
int thickness = 1,
int lineType = LINE_8,
bool bottomLeftOrigin = false
)
The parameters are:
Parameters
img Image.
text Text string to be drawn.
org Bottom-left corner of the text string in the image.
fontFace Font type, see cv::HersheyFonts.
fontScale Font scale factor that is multiplied by the font-specific base size.
color Text color.
thickness Thickness of the lines used to draw a text.
lineType Line type. See the line for details.
bottomLeftOrigin When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner.
You can find an overview of the drawing function here: https://docs.opencv.org/3.1.0/dc/da5/tutorial_py_drawing_functions.html
In your case, so long as your image covers the whole screen this allows you plot exactly where you want the text, or object or whatever you want too draw to appear.
I am trying to use this code http://androiderstuffs.blogspot.com/2016/06/detecting-rectangle-using-opencv-java.html to detect card. But instead of putting card on plane surface, I will be holding this card in hand in-front of my Head. Problem is, its not detecting card rectangle. I am new to OpenCV. See my code below, this code will highlight all found rectangles in output image. Problem is, it never find card rectangle.
private void findRectangleOpen(Bitmap image) throws Exception {
Mat tempor = new Mat();
Mat src = new Mat();
Utils.bitmapToMat(image, tempor);
Imgproc.cvtColor(tempor, src, Imgproc.COLOR_BGR2RGB);
Mat blurred = src.clone();
Imgproc.medianBlur(src, blurred, 9);
Mat gray0 = new Mat(blurred.size(), CvType.CV_8U), gray = new Mat();
List<MatOfPoint> contours = new ArrayList<MatOfPoint>();
List<Mat> blurredChannel = new ArrayList<Mat>();
blurredChannel.add(blurred);
List<Mat> gray0Channel = new ArrayList<Mat>();
gray0Channel.add(gray0);
MatOfPoint2f approxCurve;
int maxId = -1;
for (int c = 0; c < 3; c++) {
int ch[] = {c, 0};
Core.mixChannels(blurredChannel, gray0Channel, new MatOfInt(ch));
int thresholdLevel = 1;
for (int t = 0; t < thresholdLevel; t++) {
if (t == 0) {
Imgproc.Canny(gray0, gray, 10, 20, 3, true); // true ?
Imgproc.dilate(gray, gray, new Mat(), new Point(-1, -1), 1); // 1
// ?
} else {
Imgproc.adaptiveThreshold(gray0, gray, thresholdLevel,
Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C,
Imgproc.THRESH_BINARY,
(src.width() + src.height()) / 200, t);
}
Imgproc.findContours(gray, contours, new Mat(),
Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
int i = 0;
for (MatOfPoint contour : contours) {
MatOfPoint2f temp = new MatOfPoint2f(contour.toArray());
double area = Imgproc.contourArea(contour);
approxCurve = new MatOfPoint2f();
Imgproc.approxPolyDP(temp, approxCurve,
Imgproc.arcLength(temp, true) * 0.02, true);
if (approxCurve.total() == 4 && area >= 200 && area <= 40000) {
double maxCosine = 0;
List<Point> curves = approxCurve.toList();
for (int j = 2; j < 5; j++) {
double cosine = Math.abs(angle(curves.get(j % 4),
curves.get(j - 2), curves.get(j - 1)));
maxCosine = Math.max(maxCosine, cosine);
}
if (maxCosine < 0.3) {
Imgproc.drawContours(src, contours, i, new Scalar(255, 0, 0), 3);
Bitmap bmp;
bmp = Bitmap.createBitmap(src.cols(), src.rows(),
Bitmap.Config.ARGB_8888);
Utils.matToBitmap(src, bmp);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
//File origFile = getFileForSaving();
savePhoto(byteArray);
bmp.recycle();
}
}
i++;
}
}
}
}
private static double angle(org.opencv.core.Point p1, org.opencv.core.Point p2, org.opencv.core.Point p0) {
double dx1 = p1.x - p0.x;
double dy1 = p1.y - p0.y;
double dx2 = p2.x - p0.x;
double dy2 = p2.y - p0.y;
return (dx1 * dx2 + dy1 * dy2)
/ sqrt((dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2)
+ 1e-10);
}
Sample output image is:
Output of detecting rectangle
I want to create an android application. Program steps are below
Open camera
Get frames
Select a frame by touch screen
Load template image under drawable folder
Apply template matching
Show result
The mat object of template image is not empty. I check it. When I run this code, I get below error message.
Code :
public void onCameraViewStarted(int width, int height) {
mRgba = new Mat(height, width, CvType.CV_8UC4);
temp = new Mat(height, width, CvType.CV_8UC4);
}
public boolean onTouch(View v, MotionEvent event) {
int cols = mRgba.cols();
int rows = mRgba.rows();
int xOffset = (mOpenCvCameraView.getWidth() - cols) / 2;
int yOffset = (mOpenCvCameraView.getHeight() - rows) / 2;
int x = (int)event.getX() - xOffset;
int y = (int)event.getY() - yOffset;
Log.i(TAG, "Touch image coordinates: (" + x + ", " + y + ")");
if ((x < 0) || (y < 0) || (x > cols) || (y > rows)) return false;
mIsColorSelected = true;
return true; // don't need subsequent touch events
}
private static Mat readInputStreamIntoMat(InputStream inputStream) throws IOException {
// Read into byte-array
byte[] temporaryImageInMemory = readStream(inputStream);
// Decode into mat. Use any IMREAD_ option that describes your image appropriately
Mat outputImage = Highgui.imdecode(new MatOfByte(temporaryImageInMemory), Highgui.IMREAD_GRAYSCALE);
return outputImage;
}
private static byte[] readStream(InputStream stream) throws IOException {
// Copy content of the image to byte-array
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
while ((nRead = stream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
byte[] temporaryImageInMemory = buffer.toByteArray();
buffer.close();
stream.close();
return temporaryImageInMemory;
}
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
if(mIsColorSelected) {
InputStream inpT = getResources().openRawResource(R.drawable.imgt);
Mat mTemp;
try {
mRgba.copyTo(temp);
mTemp = readInputStreamIntoMat(inpT);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// / Create the result matrix
int result_cols = temp.cols() - mTemp.cols() + 1;
int result_rows = temp.rows() - mTemp.rows() + 1;
Mat result = new Mat(result_rows, result_cols, CvType.CV_32FC1);
int match_method = 4;
// / Do the Matching and Normalize
Imgproc.matchTemplate(temp, mTemp, result, match_method);
Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat());
/*
Localizing the best match with minMaxLoc
MinMaxLocResult mmr = Core.minMaxLoc(result);
Point matchLoc;
if (match_method == Imgproc.TM_SQDIFF || match_method == Imgproc.TM_SQDIFF_NORMED) {
matchLoc = mmr.minLoc;
} else {
matchLoc = mmr.maxLoc;
}/*
// / Show me what you got
Core.rectangle(temp, matchLoc, new Point(matchLoc.x + mTemp.cols(),
matchLoc.y + mTemp.rows()), new Scalar(0, 255, 0));*/
return temp;
}
else {
mRgba = inputFrame.rgba();
}
return mRgba;
}
For template matching , both source image and template image must be of same data type(1). Here your template image(mTemp) is a gray scale image and source image( mRgba / temp ) is a color image with alpha channel.
So, lets change both source and template images to be gray scale images
temp = new Mat(height, width, CvType.CV_8UC1);
and replace mRgba.copyTo(temp) with
Imgproc.cvtColor(mRgba, temp, Imgproc.COLOR_RGBA2GRAY);
I want to print some text with image which is reside on my android phone to Bluetooth printer but text is successfully printed and image is not printed on paper.
I using following code:
public class SendingdataActivity extends Activity {
/** Called when the activity is first created. */
private BluetoothAdapter mBluetoothAdapter = null;
static final UUID MY_UUID =
UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
static String address = "50:C3:00:00:00:00";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
Toast.makeText(this,
"Bluetooth is not available.",
Toast.LENGTH_LONG).show();
finish();
return;
}
if (!mBluetoothAdapter.isEnabled()) {
Toast.makeText(this,
"Please enable your BT and re-run this program.",
Toast.LENGTH_LONG).show();
finish();
return;
}
final SendData sendData = new SendData();
Button sendButton = (Button) findViewById(R.id.send);
sendButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
sendData.sendMessage();
}
});
}
class SendData extends Thread {
private BluetoothDevice device = null;
private BluetoothSocket btSocket = null;
private OutputStream outStream = null;
public SendData(){
device = mBluetoothAdapter.getRemoteDevice(address);
try
{
btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
}
catch (Exception e) {
// TODO: handle exception
}
mBluetoothAdapter.cancelDiscovery();
try {
btSocket.connect();
} catch (IOException e) {
try {
btSocket.close();
} catch (IOException e2) {
}
}
Toast.makeText(getBaseContext(), "Connected to " + device.getName(),
Toast.LENGTH_SHORT).show();
try {
outStream = btSocket.getOutputStream();
} catch (IOException e) {
}
}
public void sendMessage()
{
try {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
Bitmap bm = BitmapFactory.decodeResource(getResources(), R.drawable.white);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100,baos); //bm is the bitmap object
byte[] b = baos.toByteArray();
Toast.makeText(getBaseContext(), String.valueOf(b.length), Toast.LENGTH_SHORT).show();
outStream.write(b);
outStream.flush();
} catch (IOException e) {
}
}
}
}
This code works and print only text on paper.
Thanks.
After long time I am created an app to print image on bluetooth printer by using following steps:
1. Connect your Bluetooth device with Android phone
2. Call senddatatodevice() method when you want to send data on printer
3. code executed within senddatatodevice() is like bellow.
private static void senddatatodevice() {
// TODO Auto-generated method stub
try {
//base64 image string
String sig="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wAMAALAEAAABAA8nAQBsbHVuAAAAAAAAAAAAADhCSU0D7QAAAAAAEAEsAAAAAQABASwAAAABAAE4QklNBCYAAAAAAA4AAAAAAAAAAAAAP4AAADhCSU0EDQAAAAAABAAAAHg4QklNBBkAAAAAAAQAAAAeOEJJTQPzAAAAAAAJAAAAAAAAAAABADhCSU0ECgAAAAAAAQAAOEJJTScQAAAAAAAKAAEAAAAAAAAAAjhCSU0D9QAAAAAASAAvZmYAAQBsZmYABgAAAAAAAQAvZmYAAQChmZoABgAAAAAAAQAyAAAAAQBaAAAABgAAAAAAAQA1AAAAAQAtAAAABgAAAAAAAThCSU0D+AAAAAAAcAAA/////////////////////////////wPoAAAAAP////////////////////////////8D6AAAAAD/////////////////////////////A+gAAAAA/////////////////////////////wPoAAA4QklNBAAAAAAAAAIAAThCSU0EAgAAAAAACAAAAAAAAAAAOEJJTQQwAAAAAAAEAQEBAThCSU0ELQAAAAAABgABAAAABThCSU0ECAAAAAAAEAAAAAEAAAJAAAACQAAAAAA4QklNBB4AAAAAAAQAAAAAOEJJTQQaAAAAAANJAAAABgAAAAAAAAAAAAAAMAAAAHEAAAAKAFUAbgB0AGkAdABsAGUAZAAtADEAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAHEAAAAwAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAEAAAAAAABudWxsAAAAAgAAAAZib3VuZHNPYmpjAAAAAQAAAAAAAFJjdDEAAAAEAAAAAFRvcCBsb25nAAAAAAAAAABMZWZ0bG9uZwAAAAAAAAAAQnRvbWxvbmcAAAAwAAAAAFJnaHRsb25nAAAAcQAAAAZzbGljZXNWbExzAAAAAU9iamMAAAABAAAAAAAFc2xpY2UAAAASAAAAB3NsaWNlSURsb25nAAAAAAAAAAdncm91cElEbG9uZwAAAAAAAAAGb3JpZ2luZW51bQAAAAxFU2xpY2VPcmlnaW4AAAANYXV0b0dlbmVyYXRlZAAAAABUeXBlZW51bQAAAApFU2xpY2VUeXBlAAAAAEltZyAA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PtT8Sh2RM+sa2F8+Pqbd6LkYuNlV+lk0svrOuyxoe3/NeCipJKQ42HiYjPTxKK8esmSypjWCf6rA1CZ0npdd/wBprw6GXzPqtqYHz4+oG71bSSUpJJJJT//ZOEJJTQQhAAAAAABVAAAAAQEAAAAPAEEAZABvAGIAZQAgAFAAaABvAHQAbwBzAGgAbwBwAAAAEwBBAGQAbwBiAGUAIABQAGgAbwB0AG8AcwBoAG8AcAAgAEMAUwAzAAAAAQA4QklNBAYAAAAAAAcACAEBAAMBAP/hD89odHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDQuMS1jMDM2IDQ2LjI3NjcyMCwgTW9uIEZlYiAxOSAyMDA3IDIyOjQwOjA4ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnhhcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eGFwTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIiB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyIgZGM6Zm9ybWF0PSJpbWFnZS9qcGVnIiB4YXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzMgV2luZG93cyIgeGFwOkNyZWF0ZURhdGU9IjIwMTQtMDItMjVUMTI6MjQ6MzYrMDU6MzAiIHhhcDpNb2RpZnlEYXRlPSIyMDE0LTAyLTI1VDEyOjI0OjM2KzA1OjMwIiB4YXA6TWV0YWRhdGFEYXRlPSIyMDE0LTAyLTI1VDEyOjI0OjM2KzA1OjMwIiB4YXBNTTpEb2N1bWVudElEPSJ1dWlkOkQ3MkUyOTYyRTM5REUzMTFBQ0QxOUQzNUM5MzAwREIzIiB4YXBNTTpJbnN0YW5jZUlEPSJ1dWlkOkQ4MkUyOTYyRTM5REUzMTFBQ0QxOUQzNUM5MzAwREIzIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiIHBob3Rvc2hvcDpIaXN0b3J5PSIiIHRpZmY6T3JpZW50YXRpb249IjEiIHRpZmY6WFJlc29sdXRpb249IjMwMDAwMDAvMTAwMDAiIHRpZmY6WVJlc29sdXRpb249IjMwMDAwMDAvMTAwMDAiIHRpZmY6UmVzb2x1dGlvblVuaXQ9IjIiIHRpZmY6TmF0aXZlRGlnZXN0PSIyNTYsMjU3LDI1OCwyNTksMjYyLDI3NCwyNzcsMjg0LDUzMCw1MzEsMjgyLDI4MywyOTYsMzAxLDMxOCwzMTksNTI5LDUzMiwzMDYsMjcwLDI3MSwyNzIsMzA1LDMxNSwzMzQzMjs1NzYxNzA0NkUxNUE0RThGODE1NzcxNTIyREJFQUIzQiIgZXhpZjpQaXhlbFhEaW1lbnNpb249IjExMyIgZXhpZjpQaXhlbFlEaW1lbnNpb249IjQ4IiBleGlmOkNvbG9yU3BhY2U9IjEiIGV4aWY6TmF0aXZlRGlnZXN0PSIzNjg2NCw0MDk2MCw0MDk2MSwzNzEyMSwzNzEyMiw0MDk2Miw0MDk2MywzNzUxMCw0MDk2NCwzNjg2NywzNjg2OCwzMzQzNCwzMzQzNywzNDg1MCwzNDg1MiwzNDg1NSwzNDg1NiwzNzM3NywzNzM3OCwzNzM3OSwzNzM4MCwzNzM4MSwzNzM4MiwzNzM4MywzNzM4NCwzNzM4NSwzNzM4NiwzNzM5Niw0MTQ4Myw0MTQ4NCw0MTQ4Niw0MTQ4Nyw0MTQ4OCw0MTQ5Miw0MTQ5Myw0MTQ5NSw0MTcyOCw0MTcyOSw0MTczMCw0MTk4NSw0MTk4Niw0MTk4Nyw0MTk4OCw0MTk4OSw0MTk5MCw0MTk5MSw0MTk5Miw0MTk5Myw0MTk5NCw0MTk5NSw0MTk5Niw0MjAxNiwwLDIsNCw1LDYsNyw4LDksMTAsMTEsMTIsMTMsMTQsMTUsMTYsMTcsMTgsMjAsMjIsMjMsMjQsMjUsMjYsMjcsMjgsMzA7RjY5RTI3MkY2NzczN0M2MkI3MjNCQTdFQzg4QTM3OEIiPiA8eGFwTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0idXVpZDozRThEMUZDRUUwOURFMzExQUNEMTlEMzVDOTMwMERCMyIgc3RSZWY6ZG9jdW1lbnRJRD0idXVpZDozRThEMUZDRUUwOURFMzExQUNEMTlEMzVDOTMwMERCMyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P3hwYWNrZXQgZW5kPSJ3Ij8+/+IMWElDQ19QUk9GSUxFAAEBAAAMSExpbm8CEAAAbW50clJHQiBYWVogB84AAgAJAAYAMQAAYWNzcE1TRlQAAAAASUVDIHNSR0IAAAAAAAAAAAAAAAEAAPbWAAEAAAAA0y1IUCAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARY3BydAAAAVAAAAAzZGVzYwAAAYQAAABsd3RwdAAAAfAAAAAUYmtwdAAAAgQAAAAUclhZWgAAAhgAAAAUZ1hZWgAAAiwAAAAUYlhZWgAAAkAAAAAUZG1uZAAAAlQA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";
byte[] imageAsBytes = android.util.Base64
.decode(sig, android.util.Base64.DEFAULT);
btMap = BitmapFactory.decodeByteArray(imageAsBytes, 0,
imageAsBytes.length);
Bitmap bitmapOrg = resizeImage(btMap, 384,
150);// Bit
byte[] sendbuf = StartBmpToPrintCode(bitmapOrg, 0);
/*byte[] a=t2.getBytes();
byte[] combined = new byte[a.length + sendbuf.length];
System.arraycopy(a,0,combined,0 ,a.length);
System.arraycopy(sendbuf,0,combined,a.length,sendbuf.length);*/
mbtOutputStream = mbtSocket.getOutputStream();
mbtOutputStream.write(sendbuf);
mbtOutputStream.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static Bitmap resizeImage(Bitmap bitmap, int w, int h) {
Bitmap BitmapOrg = bitmap;
int width = BitmapOrg.getWidth();
int height = BitmapOrg.getHeight();
int newWidth = w;
int newHeight = h;
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleWidth);
Bitmap resizedBitmap = Bitmap.createBitmap(BitmapOrg, 10,10, width,
height, matrix, true);
return resizedBitmap;
}
private static byte[] StartBmpToPrintCode(Bitmap bitmap, int t) {
byte temp = 0;
int j = 7;
int start = 0;
if (bitmap != null) {
int mWidth = bitmap.getWidth();
int mHeight = bitmap.getHeight();
int[] mIntArray = new int[mWidth * mHeight];
byte[] data = new byte[mWidth * mHeight];
bitmap.getPixels(mIntArray, 0, mWidth, 0, 0, mWidth, mHeight);
encodeYUV420SP(data, mIntArray, mWidth, mHeight, t);
byte[] result = new byte[mWidth * mHeight / 8];
for (int i = 0; i < mWidth * mHeight; i++) {
temp = (byte) ((byte) (data[i] << j) + temp);
j--;
if (j < 0) {
j = 7;
}
if (i % 8 == 7) {
result[start++] = temp;
temp = 0;
}
}
if (j != 7) {
result[start++] = temp;
}
int aHeight = 24 - mHeight % 24;
byte[] add = new byte[aHeight * 48];
byte[] nresult = new byte[mWidth * mHeight / 8 + aHeight * 48];
System.arraycopy(result, 0, nresult, 0, result.length);
System.arraycopy(add, 0, nresult, result.length, add.length);
byte[] byteContent = new byte[(mWidth / 8 + 4)
* (mHeight + aHeight)];// ´òÓ¡Êý×é
byte[] bytehead = new byte[4];// ÿÐдòÓ¡Í·
bytehead[0] = (byte) 0x1f;
bytehead[1] = (byte) 0x10;
bytehead[2] = (byte) (mWidth / 8);
bytehead[3] = (byte) 0x00;
for (int index = 0; index < mHeight + aHeight; index++) {
System.arraycopy(bytehead, 0, byteContent, index * 52, 4);
System.arraycopy(nresult, index * 48, byteContent,
index * 52 + 4, 48);
}
return byteContent;
}
return null;
}
public static void encodeYUV420SP(byte[] yuv420sp, int[] rgba, int width,
int height, int t) {
final int frameSize = width * height;
int[] U, V;
U = new int[frameSize];
V = new int[frameSize];
final int uvwidth = width / 2;
int r, g, b, y, u, v;
int bits = 8;
int index = 0;
int f = 0;
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
r = (rgba[index] & 0xff000000) >> 24;
g = (rgba[index] & 0xff0000) >> 16;
b = (rgba[index] & 0xff00) >> 8;
// rgb to yuv
y = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16;
u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128;
v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128;
// clip y
// yuv420sp[index++] = (byte) ((y < 0) ? 0 : ((y > 255) ? 255 :
// y));
byte temp = (byte) ((y < 0) ? 0 : ((y > 255) ? 255 : y));
if (t == 0) {
yuv420sp[index++] = temp > 0 ? (byte) 1 : (byte) 0;
} else {
yuv420sp[index++] = temp > 0 ? (byte) 0 : (byte) 1;
}
// {
// if (f == 0) {
// yuv420sp[index++] = 0;
// f = 1;
// } else {
// yuv420sp[index++] = 1;
// f = 0;
// }
// }
}
}
f = 0;
}
I am working on one application for it I have multiple images and I want to create one image from it. I use the below code for it but the output of the single image is only vertical format.
String sdPath = Environment.getExternalStorageDirectory().getPath()
+ "/MERGE/";
BitmapFactory.Options options;
Bitmap bitmap;
ArrayList<Bitmap> myBitmapList = new ArrayList<Bitmap>();
int vWidth = 0;
int vHeight = 0;
for (int i = 1; i <= 40; i++) {
try {
options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
bitmap = BitmapFactory.decodeFile(sdPath + "img" + i + ".jpg",
options);
vWidth = bitmap.getWidth() > vWidth ? bitmap.getWidth()
: vWidth;
vHeight += bitmap.getHeight();
myBitmapList.add(bitmap);
} catch (Exception e) {
e.printStackTrace();
} finally {
options = null;
bitmap = null;
System.gc();
Runtime.getRuntime().totalMemory();
Runtime.getRuntime().freeMemory();
}
}
Bitmap vTargetBitmap = Bitmap.createBitmap(vWidth, vHeight,
Bitmap.Config.ARGB_8888);
Canvas vCanvas = new Canvas(vTargetBitmap);
int vInsertY = 0;
for (int i = 1; i < 40; i++) {
vCanvas.drawBitmap(myBitmapList.get(i), (float) 0f,
(float) vInsertY, null);
vInsertY += myBitmapList.get(i).getHeight();
}
String tmpImg = String.valueOf(System.currentTimeMillis()) + ".png";
OutputStream os = null;
try {
os = new FileOutputStream(Environment.getExternalStorageDirectory()
.getPath() + "/" + tmpImg);
vTargetBitmap.compress(CompressFormat.PNG, 50, os);
} catch (IOException e) {
Log.e("combineImages", "problem combining images", e);
}
Toast.makeText(this, "Done", Toast.LENGTH_LONG).show();
The actual output I want is something like below image.
Actual output I want is something like this
private Bitmap mergeMultiple(ArrayList<Bitmap> parts) {
Bitmap result = Bitmap.createBitmap(parts.get(0).getWidth() * 2, parts.get(0).getHeight() * 2, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
Paint paint = new Paint();
for (int i = 0; i < parts.size(); i++) {
canvas.drawBitmap(parts.get(i), parts.get(i).getWidth() * (i % 2), parts.get(i).getHeight() * (i / 2), paint);
}
return result;
}