How do I set opacity on a Bitmap? - android

I created a custom object that has a Bitmap field. I'm drawing several of these objects to the canvas of a View to mimic a scrolling horizontal image gallery.
When the user long presses one of the images, I want to change the opacity of the remaining Bitmaps to a specified percentage. This could give the impression that they've darkened for "edit mode", or it could mean they've returned to normal. (Please note that I don't want to permanently alter the Bitmaps. I want to be able to adjust their opacity on the fly.)
I pieced together the following code from various forums, and everything seems to be working except for the change in opacity. I've confirmed that my Bitmaps are mutable and have alpha every step of the way. What am I doing wrong?
Targeting Android 2.1, API Level 7
View (abridged for brevity):
public class CanvasStoryEdit2 extends View
{
public CanvasStoryEdit2(Context context, AttributeSet attrs) {
super(context, attrs);
for (int i = 0; i < getResources().getInteger(R.integer.maxAllowedSlides); i++)
{
ImageStoryEdit img = new ImageStoryEdit();
//test images
if (i == 0) { resource = R.drawable.a1; }
else if (i == 1) { resource = R.drawable.a2; }
else if (i == 2) { resource = R.drawable.a3; }
else if (i == 3) { resource = R.drawable.a4; }
else if (i == 4) { resource = R.drawable.a5; }
Bitmap bmp = BitmapFactory.decodeResource(getResources(), resource);
Log.d("TEST", "[" + Integer.toString(i) + "] - config: " + bmp.getConfig().toString());
Log.d("TEST", "[" + Integer.toString(i) + "] - hasAlpha: " + Boolean.toString(bmp.hasAlpha()));
Log.d("TEST", "[" + Integer.toString(i) + "] - isMutable: " + Boolean.toString(bmp.isMutable()));
final int imgHeight = bmp.getHeight() / (bmp.getWidth() / imgWidth);
bmp = Bitmap.createScaledBitmap(bmp, imgWidth, imgHeight, false);
Log.d("TEST", "[" + Integer.toString(i) + "] - config: " + bmp.getConfig().toString());
Log.d("TEST", "[" + Integer.toString(i) + "] - hasAlpha: " + Boolean.toString(bmp.hasAlpha()));
Log.d("TEST", "[" + Integer.toString(i) + "] - isMutable: " + Boolean.toString(bmp.isMutable()));
int width = bmp.getWidth();
int height = bmp.getHeight();
int[] pixels = new int[width * height];
bmp.getPixels(pixels, 0, width, 0, 0, width, height);
bmp.recycle();
bmp = null;
img.setBmp(Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888));
img.getBmp().setPixels(pixels, 0, width, 0, 0, width, height);
pixels = null;
Log.d("TEST", "[" + Integer.toString(i) + "] - config: " + img.getBmp().getConfig().toString());
Log.d("TEST", "[" + Integer.toString(i) + "] - hasAlpha: " + Boolean.toString(img.getBmp().hasAlpha()));
Log.d("TEST", "[" + Integer.toString(i) + "] - isMutable: " + Boolean.toString(img.getBmp().isMutable()));
imageStoryEditList.add(img);
}
}
Call made on long press:
{
img.setOpacity(50);
invalidate();
}
ImageStoryEdit (also abridged):
public class ImageStoryEdit
{
private int opacity;
public Bitmap bmp;
public Bitmap getBmp() {
return bmp;
}
public void setBmp(Bitmap bmp)
{
this.bmp = bmp;
UpdateRectF();
}
public int getOpacity()
{
return opacity;
}
public void setOpacity(int percent)
{
//ADJUST FOR RANGE OF 0-100%
percent = percent < 0 ? 0 : percent;
percent = percent > 100 ? 100 : percent;
this.opacity = percent;
int opacity = (int) (this.opacity * 2.55);
Log.d("TEST", "OPACITY = " + Integer.toString(percent) + " : " + Integer.toString(opacity));
adjustOpacity(opacity);
}
private void adjustOpacity(int opacity)
{
Log.d("TEST", "OPACITY = " + Integer.toString(opacity));
Log.d("TEST", this.bmp.getConfig().toString());
Log.d("TEST", "hasAlpha: " + Boolean.toString(this.bmp.hasAlpha()));
Log.d("TEST", "isMutable: " + Boolean.toString(this.bmp.isMutable()));
Bitmap bmp2 = this.bmp.copy(Config.ARGB_8888, true);
Canvas canvas = new Canvas(bmp2);
Paint paint = new Paint();
paint.setAlpha(opacity);
canvas.drawBitmap(bmp2, 0, 0, paint);
this.bmp = bmp2;
Log.d("TEST", this.bmp.getConfig().toString());
Log.d("TEST", "hasAlpha: " + Boolean.toString(this.bmp.hasAlpha()));
Log.d("TEST", "isMutable: " + Boolean.toString(this.bmp.isMutable()));
Log.d("TEST", "DONE");
}
}

I think I figured this one out on my own, but I welcome any feedback if anyone can offer additional insight.
I was able to do what I wanted by using a BitmapDrawable. It's a wrapper for a Bitmap. Editing the Bitmap itself is, indeed, permanent. BitmapDrawables allow you to change certain parameters without directly affecting the underlying Bitmap.

Related

Android : How to put object on particular location of screen using openCv?

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.

how to determine width and height of rectangle drawn on bitmap in a imageview

this is the code i am using to get starting x,y coordinates. i also need width and height of rectangle drawn.
this code i have taken from a website link- http://android-er.blogspot.in/2013/09/detect-touch-and-draw-rect-on-bitmap.html
please provide solution
public class MainActivity extends Activity {
Button btnLoadImage;
TextView textSource;
ImageView imageResult, imageDrawingPane;
final int RQS_IMAGE1 = 1;
Uri source;
Bitmap bitmapMaster;
Canvas canvasMaster;
Bitmap bitmapDrawingPane;
Canvas canvasDrawingPane;
projectPt startPt;
projectPt endpt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnLoadImage = (Button)findViewById(R.id.loadimage);
textSource = (TextView)findViewById(R.id.sourceuri);
imageResult = (ImageView)findViewById(R.id.result);
imageDrawingPane = (ImageView)findViewById(R.id.drawingpane);
btnLoadImage.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, RQS_IMAGE1);
}});
imageResult.setOnTouchListener(new OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
switch(action){
case MotionEvent.ACTION_DOWN:
textSource.setText("ACTION_DOWN- " + x + " : " + y);
startPt = projectXY((ImageView)v, bitmapMaster, x, y);
break;
case MotionEvent.ACTION_MOVE:
textSource.setText("ACTION_MOVE- " + x + " : " + y);
drawOnRectProjectedBitMap((ImageView)v, bitmapMaster, x, y);
break;
case MotionEvent.ACTION_UP:
textSource.setText("ACTION_UP- " + x + " : " + y);
drawOnRectProjectedBitMap((ImageView)v, bitmapMaster, x, y);
finalizeDrawing();
break;
}
return true;
}});
}
class projectPt{
int x;
int y;
projectPt(int tx, int ty){
x = tx;
y = ty;
}
}
private projectPt projectXY(ImageView iv, Bitmap bm, int x, int y){
if(x<0 || y<0 || x > iv.getWidth() || y > iv.getHeight()){
//outside ImageView
return null;
}else{
int projectedX = (int)((double)x * ((double)bm.getWidth()/(double)iv.getWidth()));
int projectedY = (int)((double)y * ((double)bm.getHeight()/(double)iv.getHeight()));
return new projectPt(projectedX, projectedY);
}
}
private void drawOnRectProjectedBitMap(ImageView iv, Bitmap bm, int x, int y){
if(x<0 || y<0 || x > iv.getWidth() || y > iv.getHeight()){
//outside ImageView
return;
}else{
int projectedX = (int)((double)x * ((double)bm.getWidth()/(double)iv.getWidth()));
int projectedY = (int)((double)y * ((double)bm.getHeight()/(double)iv.getHeight()));
//clear canvasDrawingPane
canvasDrawingPane.drawColor(Color.TRANSPARENT, Mode.CLEAR);
Paint paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.WHITE);
paint.setStrokeWidth(4);
canvasDrawingPane.drawRect(startPt.x, startPt.y, projectedX, projectedY, paint);
imageDrawingPane.invalidate();
// textSource.setText(x + ":" + y + "/" + iv.getWidth() + " : " + iv.getHeight() + "\n" +
// projectedX + " : " + projectedY + "/" + bm.getWidth() + " : " + bm.getHeight()
textSource.setText(startPt.x + ":" + startPt.y + "/" + iv.getWidth() + " : " + iv.getHeight() + "\n" +
projectedX + " : " + projectedY+ "/" + bm.getWidth() + " : " + bm.getHeight()
);
}
}
private void finalizeDrawing(){
canvasMaster.drawBitmap(bitmapDrawingPane, 0, 0, null);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Bitmap tempBitmap;
if(resultCode == RESULT_OK){
switch (requestCode){
case RQS_IMAGE1:
source = data.getData();
textSource.setText(source.toString());
try {
tempBitmap = BitmapFactory.decodeStream(
getContentResolver().openInputStream(source));
Config config;
if(tempBitmap.getConfig() != null){
config = tempBitmap.getConfig();
}else{
config = Config.ARGB_8888;
}
bitmapMaster = Bitmap.createBitmap(
tempBitmap.getWidth(),
tempBitmap.getHeight(),
config);
canvasMaster = new Canvas(bitmapMaster);
canvasMaster.drawBitmap(tempBitmap, 0, 0, null);
imageResult.setImageBitmap(bitmapMaster);
bitmapDrawingPane = Bitmap.createBitmap(
tempBitmap.getWidth(),
tempBitmap.getHeight(),
config);
canvasDrawingPane = new Canvas(bitmapDrawingPane);
imageDrawingPane.setImageBitmap(bitmapDrawingPane);
}
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}
}
}
Before drawing
Rect rect = new Rect(startPt.x, startPt.y, projectedX, projectedY);
canvasDrawingPane.drawRect(rect,paint);
width = rect.width();
height = rect.height();
imageDrawingPane.invalidate();
Here is your answer.
Here int projectedX and int int projectedY contains width and height of rectangle drawn.
You can make both global and access anywhere in the class.
Like this..
//rectangle width and height
int projectedX;
int projectedY;
//end
Button btnLoadImage;
TextView textSource;
ImageView imageResult, imageDrawingPane;
Now access projectedX & projectedY to get width and height anywhere.

Android layout not aligned parent as instructed in java code

I am having problem inflating my CustomView programmatically from the XML layout that I specify.
I have a CustomView which extends RelativeLayout and contains another RelativeLayout which in turns contain 2 ImageView and 1 LinearLayout. The ImageViews are arrow Icons which I put to the left and right of the parent by android:layout_alignParentLeft="true" and android:layout_alignParentRight="true" respectively, and the LinearLayout is used to fill all the space in between.
To make it clear, here is the xml layout view in the Eclipse Layout Designer, which is what I intended it to be...
If I setContentView(R.layout.my_xml_layout); directly from the Activity, everything appears as shown in Eclipse Layout Designer, however, if I inflate the R.layout.my_xml_layout from my CustomView's constructor, there is a stubborn margin to the left and right of the ImageView that cannot go away.
This is done in java code, and is problematic:
Any help will be highly appreciated! Thanks in advance!
my_xml_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<ImageView
android:id="#+id/imageLeftArrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:src="#drawable/dock_leftarrow" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
</LinearLayout>
<ImageView
android:id="#+id/imageRightArrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:src="#drawable/dock_rightarrow" />
</RelativeLayout>
</RelativeLayout>
I inflate it in the CustomView's Constructor through this line:
View.inflate( mContext, R.layout.my_xml_layout, this );
My CustomView's onLayout:
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// Do nothing. Do not call the superclass method--that would start a layout pass
// on this view's children. PieChart lays out its children in onSizeChanged().
Log.e("DrawView", "DrawView.onLayout: " + l + ", " + t + ", " + r + ", " + b);
int iChildCount = this.getChildCount();
for ( int i = 0; i < iChildCount; i++ ) {
View pChild = this.getChildAt(i);
pChild.layout(0, 0, pChild.getMeasuredWidth(), pChild.getMeasuredHeight());
}
}
My CustomView's onMeasure:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Try for a width based on our minimum
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Log.d("DockView", "DockView.onMeasure: width: " + widthMeasureSpec + " getWidth: " + MeasureSpec.getSize(widthMeasureSpec));
Log.d("DockView", "DockView.onMeasure: height: " + heightMeasureSpec + " getHeight: " + MeasureSpec.getSize(heightMeasureSpec));
Log.d("DockView", "DockView.onMeasure: getPaddingLeft: " + getPaddingLeft() + " getPaddingRight: " + getPaddingRight());
Log.d("DockView", "DockView.onMeasure: getPaddingTop: " + getPaddingTop() + " getPaddingBottom: " + getPaddingBottom());
// http://stackoverflow.com/a/17545273/474330
int iParentWidth = MeasureSpec.getSize(widthMeasureSpec);
int iParentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(iParentWidth, iParentHeight);
int iChildCount = this.getChildCount();
for ( int i = 0; i < iChildCount; i++ ) {
View pChild = this.getChildAt(i);
this.measureChild( pChild,
MeasureSpec.makeMeasureSpec(iParentWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(iParentHeight, MeasureSpec.EXACTLY)
);
}
}
For the time being, I am resorting to a hack.
I only add the LinearLayout as subview of my CustomView. Then I manually render the two ImageViews in onDraw(Canvas c); function of my CustomView. And in order to get the LinearLayout to fit into the remaining space between the two ImageViews, I calculate the margin of the LinearLayout in my CustomView's onLayout.
horizontal_dock_view.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#android:color/white" >
<ImageView
android:id="#+id/imageLauncher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/ic_launcher"/>
</LinearLayout>
</RelativeLayout>
CustomView.java
/**
* Initialize the control. This code is in a separate method so that it can be
* called from both constructors.
*/
private void init() {
setWillNotDraw( false );
// Load the arrow bitmap
mArrowBitmap = ((BitmapDrawable)mContext.getResources().getDrawable(R.drawable.dock_leftarrow)).getBitmap();
ViewGroup pRootView = (ViewGroup) View.inflate( mContext, R.layout.horizontal_dock_view, this );
Log.d("DockView", "DockView.init: " + pRootView.getClass().getCanonicalName());
mIconContainerView = (LinearLayout) ((RelativeLayout)pRootView.getChildAt(0)).getChildAt(0);
Log.d("DockView", "DockView.init: " + mIconContainerView.getClass().getCanonicalName());
// if ( mArrowBitmap != null ) {
// // set the icon container margin
// float fWidth = this.getWidth(); // View's width
// float fHeight = this.getHeight(); // View's height
// float fScale = fHeight / mArrowBitmap.getHeight();
// float fArrowWidth = mArrowBitmap.getWidth() * fScale;
// float fArrowHeight = mArrowBitmap.getHeight() * fScale;
// Log.d("DockView", "DockView.init: " + fArrowWidth + ", " + fArrowHeight );
// ((RelativeLayout.LayoutParams)mIconContainerView.getLayoutParams()).setMargins((int)fArrowWidth, 0, (int)fArrowWidth, 0);
// }
}
CustomView.onLayout:
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// Do nothing. Do not call the superclass method--that would start a layout pass
// on this view's children. PieChart lays out its children in onSizeChanged().
Log.e("DrawView", "DrawView.onLayout: " + l + ", " + t + ", " + r + ", " + b);
if ( mIconContainerView != null && mArrowBitmap != null ) {
// set the icon container margin
float fHeight = this.getHeight();
float fScale = fHeight / mArrowBitmap.getHeight();
float fArrowWidth = mArrowBitmap.getWidth() * fScale;
float fArrowHeight = mArrowBitmap.getHeight() * fScale;
Log.d("DockView", "DockView.init: " + fArrowWidth + ", " + fArrowHeight );
((RelativeLayout.LayoutParams)mIconContainerView.getLayoutParams()).setMargins((int)fArrowWidth, 0, (int)fArrowWidth, 0);
this.requestLayout();
}
int iChildCount = this.getChildCount();
for ( int i = 0; i < iChildCount; i++ ) {
View pChild = this.getChildAt(i);
pChild.layout(0, 0, pChild.getMeasuredWidth(), pChild.getMeasuredHeight());
}
}
CustomView.onDraw
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// mBgColor = Color.CYAN;
// Log.e("DockView", "DockView.onDraw: " + mBgColor);
Log.e("DockView", "DockView.onDraw: width: " + this.getWidth() + " height: " + this.getHeight());
// debugChildren( (RelativeLayout) ((RelativeLayout)this.getChildAt(0)).getChildAt(0) );
debugChildren( ((RelativeLayout)this.getChildAt(0)) );
// draw the background
canvas.drawColor( mBgColor );
float fWidth = this.getWidth(); // View's width
float fHeight = this.getHeight(); // View's height
{
// draw the dock
float fTop = (2 * fHeight) / 3.0f;
Shader shader = new LinearGradient( 0, fTop, 0, fHeight, mDockTopGradientColor, mDockBottomGradientColor, TileMode.CLAMP );
Paint paint = new Paint();
paint.setShader(shader);
canvas.drawRect( new RectF( 0, fTop, fWidth, fHeight ), paint );
}
// moved to onLayout
// if ( mIconContainerView != null && mArrowBitmap != null ) {
// // set the icon container margin
// float fScale = fHeight / mArrowBitmap.getHeight();
// float fArrowWidth = mArrowBitmap.getWidth() * fScale;
// float fArrowHeight = mArrowBitmap.getHeight() * fScale;
// Log.d("DockView", "DockView.init: " + fArrowWidth + ", " + fArrowHeight );
// ((RelativeLayout.LayoutParams)mIconContainerView.getLayoutParams()).setMargins((int)fArrowWidth, 0, (int)fArrowWidth, 0);
// this.requestLayout();
// }
if ( mArrowBitmap != null ) {
// draw the arrow
// canvas.drawBitmap(mArrowBitmap, 0, 0, null);
float fScale = fHeight / mArrowBitmap.getHeight();
float fDrawnWidth = mArrowBitmap.getWidth() * fScale;
float fDrawnHeight = mArrowBitmap.getHeight() * fScale;
// float fLeft = fWidth - fDrawnWidth;
// float fTop = 0.0f;
// float fRight = fWidth;
// float fBottom = fDrawnHeight;
// Log.d("DockView", "DockView.onDraw: (" + fLeft + ", " + fTop + ", " + fRight + ", " + fBottom + ")");
canvas.drawBitmap(mArrowBitmap, null, new RectF(0, 0, fDrawnWidth, fDrawnHeight), null); // Left arrow
Log.d("DockView", "DockView.onDraw: (" + 0 + ", " + 0 + ", " + fDrawnWidth + ", " + fDrawnHeight + ")");
canvas.save();
canvas.scale(-1,1);
canvas.translate(-fWidth, 0);
// canvas.drawBitmap(mArrowBitmap, null, new RectF(fLeft, fTop, fRight, fBottom), null);
canvas.drawBitmap(mArrowBitmap, null, new RectF(0, 0, fDrawnWidth, fDrawnHeight), null); // Right arrow, flipped
canvas.restore();
}
}

Determining the entry shown is listview

i am trying to send data in a listview when a button is clicked.
However my listview show 2 row on at once one full row and one partial row . Is there a way i can determine which row is showing partial and which is showing fully.
I am able to get the index that is showing only. is there another approach ?
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE){
Rect r = new Rect ();
View child = recordListview.getChildAt(view.getFirstVisiblePosition()); // first visible child
if (child == null)
return;
double height = child.getHeight () * 1.0;
recordListview.getChildVisibleRect (child, r, null);
Log.d("Visible1 ", view.getFirstVisiblePosition() + " " + height + " " + r.height() );
if (Math.abs (r.height ()) < height / 2.0) {
// show next child
recordListview.smoothScrollToPosition(view.getFirstVisiblePosition()+1);
Log.d("Visible1 Location", view.getFirstVisiblePosition() +1+ "");
}
else {
recordListview.smoothScrollToPosition(view.getFirstVisiblePosition());
Log.d("Visible1 Location", view.getFirstVisiblePosition()+ "");
}
}
}
});
Seems You've understood documentation of getChildVisibleRect() incorrectly.
It mentions:
r The input rectangle, defined in the child coordinate system. Will
be overwritten to contain the resulting visible rectangle, expressed
in global (root) coordinates
So, if You're providing empty rectangle in the child coordinate then it can be translated only into empty visible rectagle, right?
For me this code seems to work:
recordListview.setOnScrollListener(new AbsListView.OnScrollListener() {
#Override
public void onScrollStateChanged(final AbsListView view, final int scrollState) {
if (scrollState == SCROLL_STATE_IDLE) {
final View child = recordListview.getChildAt(view.getFirstVisiblePosition());
if (child == null) {
return;
}
final Rect r = new Rect (0, 0, child.getWidth(), child.getHeight());
final double height = child.getHeight () * 1.0;
recordListview.getChildVisibleRect(child, r, null);
Log.d("Visible1 ", view.getFirstVisiblePosition() + " " + height + " " + r.height());
if (Math.abs (r.height ()) < height / 2.0) {
// show next child
recordListview.smoothScrollToPosition(view.getFirstVisiblePosition()+1);
Log.d("Visible1 Location", view.getFirstVisiblePosition() +1+ "");
} else {
recordListview.smoothScrollToPosition(view.getFirstVisiblePosition());
Log.d("Visible1 Location", view.getFirstVisiblePosition()+ "");
}
}
}
#Override
public void onScroll(final AbsListView view, final int firstVisibleItem, final int visibleItemCount, final int totalItemCount) {
// nothing to do here
}
});
Regarding initial question about determining which view is visible fully and which is not, I would suggest to use the following code:
#Override
public void onScrollStateChanged(final AbsListView view, final int scrollState) {
if (scrollState == SCROLL_STATE_IDLE) {
final int firstVisiblePosition = view.getFirstVisiblePosition();
View child = recordListview.getChildAt(firstVisiblePosition);
if (child == null) {
return;
}
if (mListItemsOnScreen == 0) {
// number of total visible items, including items which are not fully visible
mListItemsOnScreen = (int) Math.ceil(((double)recordListview.getHeight()) / (child.getHeight() + recordListview.getDividerHeight()));
}
final Rect r = new Rect(0, 0, child.getWidth(), child.getHeight());
final double height = child.getHeight();
recordListview.getChildVisibleRect(child, r, null);
Log.d("Visible1", " items till " + firstVisiblePosition + " are not visible");
// Check top item
Log.d("Visible1", firstVisiblePosition + " is visible " + (r.height() >= height ? " fully" : "partially"));
// check bottom item
child = recordListview.getChildAt(firstVisiblePosition + mListItemsOnScreen);
if (child != null) {
r.set(0, 0, child.getWidth(), child.getHeight());
recordListview.getChildVisibleRect(child, r, null);
Log.d("Visible1", " items from " + firstVisiblePosition + " till " + (firstVisiblePosition + mListItemsOnScreen) + " are fully visible");
Log.d("Visible1", (firstVisiblePosition + mListItemsOnScreen) + " is visible " + (r.height() >= height ? " fully" : "partially"));
} else {
Log.d("Visible1", " items from " + firstVisiblePosition + " till " + (firstVisiblePosition + mListItemsOnScreen) + " are fully visible");
Log.d("Visible1", (firstVisiblePosition + mListItemsOnScreen) + " is invisible ");
}
}
}

Android Face detection only works with drawables not with images from SD card

So I have code to detect up to 10 faces in any given image file and return to me info like the location of the eyes and other stuff like that. So when i tell it to use an image file that is stored in the drawable folder of resources for my project it works great. But when i have it try to find faces from a bitmap i import from the sd card it wont find any faces. But these are the same exact images. Any ideas? my code is bellow:
Edit:
After further inspection I found that when i insert this line of code System.out.println("Row Bytes: " + sourceImage.getRowBytes());
I get the drawable is 352 and The SD card image is 704. Which I think means that the drawable is being compressed in the .apk file but the SD card image obviously is not. Not sure if this would effect anything.
public class FaceView extends View {
private static final int NUM_FACES = 10; // max is 64
private static final boolean DEBUG = true;
private FaceDetector arrayFaces;
private FaceDetector.Face getAllFaces[] = new FaceDetector.Face[NUM_FACES];
private FaceDetector.Face getFace = null;
private PointF eyesMidPts[] = new PointF[NUM_FACES];
private float eyesDistance[] = new float[NUM_FACES];
private Bitmap sourceImage;
private Paint tmpPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint pOuterBullsEye = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint pInnerBullsEye = new Paint(Paint.ANTI_ALIAS_FLAG);
private int picWidth, picHeight;
private float xRatio, yRatio;
public FaceView(Context context) {
super(context);
pInnerBullsEye.setStyle(Paint.Style.FILL);
pInnerBullsEye.setColor(Color.RED);
pOuterBullsEye.setStyle(Paint.Style.STROKE);
pOuterBullsEye.setColor(Color.RED);
tmpPaint.setStyle(Paint.Style.STROKE);
tmpPaint.setTextAlign(Paint.Align.CENTER);
BitmapFactory.Options bfo = new BitmapFactory.Options();
bfo.inPreferredConfig = Bitmap.Config.RGB_565;
//********This code imports the image from the SD card which does not work
String imageInSD = Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/testfolder/" + "face1" + ".png";
Bitmap sourceImage = BitmapFactory.decodeFile(imageInSD,bfo);
//**********This code uses an image in the projects drawable folder, this code works.
sourceImage = BitmapFactory.decodeResource( getResources() ,R.drawable.face1, bfo);
picWidth = sourceImage.getWidth();
picHeight = sourceImage.getHeight();
arrayFaces = new FaceDetector( picWidth, picHeight, NUM_FACES );
arrayFaces.findFaces(sourceImage, getAllFaces);
for (int i = 0; i < getAllFaces.length; i++)
{
getFace = getAllFaces[i];
try {
PointF eyesMP = new PointF();
getFace.getMidPoint(eyesMP);
eyesDistance[i] = getFace.eyesDistance();
eyesMidPts[i] = eyesMP;
if (DEBUG)
{
Log.i("Face",
i + " " + getFace.confidence() + " " + getFace.eyesDistance() + " "
+ "Pose: ("+ getFace.pose(FaceDetector.Face.EULER_X) + ","
+ getFace.pose(FaceDetector.Face.EULER_Y) + ","
+ getFace.pose(FaceDetector.Face.EULER_Z) + ")"
+ "Eyes Midpoint: ("+eyesMidPts[i].x + "," + eyesMidPts[i].y +")"
);
}
}
catch (Exception e)
{
if (DEBUG) Log.e("Face", i + " is null");
}
}
}
#Override
protected void onDraw(Canvas canvas)
{
xRatio = getWidth()*1.0f / picWidth;
yRatio = getHeight()*1.0f / picHeight;
canvas.drawBitmap( sourceImage, null , new Rect(0,0,getWidth(),getHeight()),tmpPaint);
for (int i = 0; i < eyesMidPts.length; i++)
{
if (eyesMidPts[i] != null)
{
pOuterBullsEye.setStrokeWidth(eyesDistance[i] /6);
canvas.drawCircle(eyesMidPts[i].x*xRatio, eyesMidPts[i].y*yRatio, eyesDistance[i] / 2 , pOuterBullsEye);
canvas.drawCircle(eyesMidPts[i].x*xRatio, eyesMidPts[i].y*yRatio, eyesDistance[i] / 6 , pInnerBullsEye);
}
}
}
}
Alright I believe I know what your issue is here. The device can not render the image to a bitmap image as it sits in external memory. The face recognition is working its just not making it to the canvas. All devices have a rendering limit on my xoom its (2048x2048) I found that here. The reason that it works when you add the image as a resource is because your file is downsized as it builds the .apk (to be honest I'm not sure why it does this, but I left a little println for testing, someone else could answer that better). Anyway I just scaled the bitmap by dividing by 2 after your code looked for faces and before it tries to render the bitmap to the canvas. Now everything seems to work fine. You may want to adjust your face indicators but its functional. I hope this helps.
public class FaceView extends View {
private static final int NUM_FACES = 1; // max is 64
private static final boolean DEBUG = true;
private FaceDetector arrayFaces;
private FaceDetector.Face getAllFaces[] = new FaceDetector.Face[NUM_FACES];
private FaceDetector.Face getFace = null;
private PointF eyesMidPts[] = new PointF[NUM_FACES];
private float eyesDistance[] = new float[NUM_FACES];
private Bitmap sourceImage;
private Paint tmpPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint pOuterBullsEye = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint pInnerBullsEye = new Paint(Paint.ANTI_ALIAS_FLAG);
private int picWidth, picHeight;
private float xRatio, yRatio;
public FaceView(Context context) {
super(context);
pInnerBullsEye.setStyle(Paint.Style.FILL);
pInnerBullsEye.setColor(Color.RED);
pOuterBullsEye.setStyle(Paint.Style.STROKE);
pOuterBullsEye.setColor(Color.RED);
tmpPaint.setStyle(Paint.Style.STROKE);
tmpPaint.setTextAlign(Paint.Align.CENTER);
BitmapFactory.Options bfo = new BitmapFactory.Options();
bfo.inPreferredConfig = Bitmap.Config.RGB_565;
//********This code imports the image from the SD card which does not work
String imageInSD = Environment.getExternalStorageDirectory().getAbsolutePath() + "/face1" + ".jpg";
System.out.println(imageInSD);
sourceImage = BitmapFactory.decodeFile(imageInSD, bfo);
//Bitmap sourceImage;// = BitmapFactory.decodeFile(imageInSD,bfo);
//**********This code uses an image in the projects drawable folder, this code works.
//sourceImage = BitmapFactory.decodeResource( getResources() ,R.drawable.face1, bfo);
picWidth = sourceImage.getWidth();
picHeight = sourceImage.getHeight();
System.out.println(picWidth + "x" + picHeight);
arrayFaces = new FaceDetector( picWidth, picHeight, NUM_FACES );
arrayFaces.findFaces(sourceImage, getAllFaces);
sourceImage = Bitmap.createScaledBitmap (sourceImage, picWidth/2, picHeight/2, false);
for (int i = 0; i < getAllFaces.length; i++)
{
getFace = getAllFaces[i];
try {
PointF eyesMP = new PointF();
getFace.getMidPoint(eyesMP);
eyesDistance[i] = getFace.eyesDistance();
eyesMidPts[i] = eyesMP;
if (DEBUG)
{
Log.i("Face",
i + " " + getFace.confidence() + " " + getFace.eyesDistance() + " "
+ "Pose: ("+ getFace.pose(FaceDetector.Face.EULER_X) + ","
+ getFace.pose(FaceDetector.Face.EULER_Y) + ","
+ getFace.pose(FaceDetector.Face.EULER_Z) + ")"
+ "Eyes Midpoint: ("+eyesMidPts[i].x + "," + eyesMidPts[i].y +")"
);
}
}
catch (Exception e)
{
if (DEBUG) Log.e("Face", i + " is null");
}
}
}
#Override
protected void onDraw(Canvas canvas)
{
xRatio = getWidth()*1.0f / picWidth;
yRatio = getHeight()*1.0f / picHeight;
canvas.drawBitmap( sourceImage, null , new Rect(0,0,getWidth(),getHeight()),tmpPaint);
for (int i = 0; i < eyesMidPts.length; i++)
{
if (eyesMidPts[i] != null)
{
pOuterBullsEye.setStrokeWidth(eyesDistance[i] /6);
canvas.drawCircle(eyesMidPts[i].x*xRatio, eyesMidPts[i].y*yRatio, eyesDistance[i] / 2 , pOuterBullsEye);
canvas.drawCircle(eyesMidPts[i].x*xRatio, eyesMidPts[i].y*yRatio, eyesDistance[i] / 6 , pInnerBullsEye);
}
}
}
}
Turns out the issue is that the pictures taken by the Camera are saved as PNG files and the face detection can only successfully work from the SD card if it is using JPG files. Simply convert the files to JPG and it works fine.

Categories

Resources