I want to change the HSV of bitmap I found out some help online but they are changing the HSV of whole image. In my case i have circular selector that enable user to select specific part of image and than change its HSV. It look like this
Can we do that without using any other third party image processing library?
If you know how to specifically get the pixel indices of the circle here is what you do:
int pixel = bitmap.getPixel(X,Y);
float[] HSV=new float[3];
Color.RGBToHSV(Color.red(pixel), Color.green(pixel), Color.blue(pixel), HSV);
// Manipulate the HSV array as you want then,
bitmap.setPixel(X,Y, Color.HSVToColor(HSV));
PS: If you want to know how to get the X and Y coordinates of pixel please do comment. I'll edit the post as per your requirements.
EDIT :
Here is how you get pixels of the circular area (and manipulate it) provided you have the co-ordinate of the center of the circle and the radius of the circle you want the manipulation to.
int centerX = 100; // This is the X co-ordinate of the center of your circle
int centerY = 100; // This is the Y co-ordinate of the center of your circle
int radius = 40; // This is the radius of the circle you want
for(int Y=centerY-radius; Y<=centerY+radius;Y++)
{
for(int X=centerX-radius;X<=centerX+radius;X++)
{
int distance = (int)Math.sqrt(Math.pow((X-centerX),2) + Math.pow((Y-centerY),2));
if(distance<=radius)
{
int pixel = bitmap.getPixel(X,Y);
float[] HSV=new float[3];
Color.RGBToHSV(Color.red(pixel), Color.green(pixel), Color.blue(pixel), HSV);
// Manipulate the HSV array as you want then,
bitmap.setPixel(X,Y, Color.HSVToColor(Color.alpha(pixel),HSV));
}
}
}
you can use Bitmap.setPixel(int, int, int); , to change the color at position(x, y).
or
you can create a canvas use from a bitmap use
Canvas canvas = new Canvas(bitmap);
and you can add new content on the original bitmap.
Related
I'm doing a simple android animation using my self-customized VIEW. I have two circles drawn on the onDraw() method of the class extends to View class. The one circle is moving upon dragging using MotionEvent while the other one is static on a certain position. If the moving circle touches any point of a static circle, the color of the moving circle will change to the color of the static circle.
For example
int_circle_radius= 50;
int circle1_x = 0;
int circle1_y = 0;
int circle2_x = 200;
int circle2_y = 200;
let's assume that the moving circle which is the circle 1 was drag and drop to a certain point of the circle 2.
I tried using the below formula but the circle 1's color only change if it really goes to the exact location of the circle 2.
if (circle1_x == circle1_x && circle1_y == circle2_y){
paint.setColor(Color.RED);
}
I know that the problem here is a circle has many points from it's radius, but how can I trigger a specific action if the a circle touches any of his point to another circle? Thanks.
You can simply calculate the distance between the centers of the two circles. If the distance is less than two times the radius, the circles are intersecting. Calculating that is easy. You can not expect to get the exact MotionEvent where the circles distance equals the double radius, so you have to check for a distance that is less or equal:
int deltaX = circle1_x - circle2_x;
int deltaY = circle1_y - circle2_y;
if(Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)) <= 2 * circle_radius) {
paint.setColor(Color.RED);
}
I am trying to implement a 3D app for Android that should also support cardboard like viewers. I have seen some of those images and they seem to have some kind of barrel distortion in order to be orthogonal through the cardboard lenses.
So I was looking for algorithms or libraries specifically for Java/Android that would help me achieving this.
I have found this implementation: http://www.helviojunior.com.br/fotografia/barrel-and-pincushion-distortion/
It would be great to have something like this because it has everything I'd need. Unfortunately it's for C# and it has some specific code that I just couldn't easily translate into more generic code.
Then there is a simpler Java implementation here: http://popscan.blogspot.de/2012/04/fisheye-lens-equation-simple-fisheye.html
I have changed it to:
public static Bitmap fisheye(Bitmap srcimage) {
/*
* Fish eye effect
* tejopa, 2012-04-29
* http://popscan.blogspot.com
* http://www.eemeli.de
*/
// get image pixels
double w = srcimage.getWidth();
double h = srcimage.getHeight();
int[] srcpixels = new int[(int)(w*h)];
srcimage.getPixels(srcpixels, 0, (int)w, 0, 0, (int)w, (int)h);
Bitmap resultimage = srcimage.copy(srcimage.getConfig(), true);
// create the result data
int[] dstpixels = new int[(int)(w*h)];
// for each row
for (int y=0;y<h;y++) {
// normalize y coordinate to -1 ... 1
double ny = ((2*y)/h)-1;
// pre calculate ny*ny
double ny2 = ny*ny;
// for each column
for (int x=0;x<w;x++) {
// preset to black
dstpixels[(int)(y*w+x)] = 0;
// normalize x coordinate to -1 ... 1
double nx = ((2*x)/w)-1;
// pre calculate nx*nx
double nx2 = nx*nx;
// calculate distance from center (0,0)
// this will include circle or ellipse shape portion
// of the image, depending on image dimensions
// you can experiment with images with different dimensions
double r = Math.sqrt(nx2+ny2);
// discard pixels outside from circle!
if (0.0<=r&&r<=1.0) {
double nr = Math.sqrt(1.0-r*r);
// new distance is between 0 ... 1
nr = (r + (1.0-nr)) / 2.0;
// discard radius greater than 1.0
if (nr<=1.0) {
// calculate the angle for polar coordinates
double theta = Math.atan2(ny,nx);
// calculate new x position with new distance in same angle
double nxn = nr*Math.cos(theta);
// calculate new y position with new distance in same angle
double nyn = nr*Math.sin(theta);
// map from -1 ... 1 to image coordinates
int x2 = (int)(((nxn+1)*w)/2.0);
// map from -1 ... 1 to image coordinates
int y2 = (int)(((nyn+1)*h)/2.0);
// find (x2,y2) position from source pixels
int srcpos = (int)(y2*w+x2);
// make sure that position stays within arrays
if (srcpos>=0 & srcpos < w*h) {
// get new pixel (x2,y2) and put it to target array at (x,y)
dstpixels[(int)(y*w+x)] = srcpixels[srcpos];
}
}
}
}
}
resultimage.setPixels(dstpixels, 0, (int)w, 0, 0, (int)w, (int)h);
//return result pixels
return resultimage;
}
But it doesn't have this lens factor, so the resulting image is always a full circle/ellipse.
Any chance you could point me to some working Java code or library or (maybe even better) help me to amend this code for the lens factor to be taken into account (0.0 <= factor <= 1.0)?
I managed to get it to work.
Bottom line: I created a Bitmap bigger than the original Bitmap, and then I drew the original Bitmap on the new Bitmap (and centered it there) using
Canvas canvas = new Canvas(newBitmap);
canvas.drawBitmap(originalBitmap, null, new Rect(x, y, r, b), null);
I used the Java algorithm posted in my question to create the effect on the new Bitmap. That worked great.
I am trying to randomize the position of a few textviews inside a frameview. The textviews will also have a randomized rotation between 0 and 360 degrees. The textViews is not allowed to be on top of eachother which means I need to check for collisions (or at least know which points that are valid/not valid). I do not know how to check for collision between two textviews when they are rotated. I have tried to use Rect intersects but this does not really work because this function only works if there is no rotation to the view.
Here is an example on what i want:
TEXT1 is placed first. When TEXT2 is placed the green border around the TEXT1 and TEXT2 is colliding which means that TEXT2 should not be allowed to be placed there. TEXT3 does however not collide with anything and should be allowed to be placed. So I want to check the collision for the green border and not the blue rectangle. How do I do this?
Edit
To rotate the view I am using View.setRotation(float)
To position the textview I am using setX(float) and setY(float).
I ended up with the following solution where I create 4 points, one for each corner of the textView, which I then rotate at the same angle as the textView. With these points I then create a Path which I am using to create a region.
private Region createRotatedRegion(TextView textView){
Matrix matrix = new Matrix();
matrix.setRotate(textView.getRotation(), textView.getX() + textView.getMeasuredWidth() / 2, textView.getY() + textView.getMeasuredHeight() / 2);
Path path = new Path();
Point LT = rotatePoint(matrix, textView.getX(), textView.getY());
Point RT = rotatePoint(matrix, textView.getX() + textView.getMeasuredWidth(), textView.getY());
Point RB = rotatePoint(matrix, textView.getX() + textView.getMeasuredWidth(), textView.getY() + textView.getMeasuredHeight());
Point LB = rotatePoint(matrix, textView.getX(), textView.getY() + textView.getMeasuredHeight());
path.moveTo(LT.x, LT.y);
path.lineTo(RT.x, RT.y);
path.lineTo(RB.x, RB.y);
path.lineTo(LB.x, LB.y);
Region region = new Region();
region.setPath(path, new Region(0, 0, textViewParent.getWidth(), textViewParent.getHeight()));
return region;
}
private Point rotatePoint(Matrix matrix, float x, float y){
float[] pts = new float[2];
pts[0] = x;
pts[1] = y;
matrix.mapPoints(pts);
return new Point((int)pts[0], (int)pts[1]);
}
When I have two regions which now have the same position and rotation as two textViews I can then use the following code to check for collision:
if (!region1.quickReject(region2) && region1.op(region2, Region.Op.INTERSECT)) {
return true; //There is a collision
}
Probably not the best solution but it gets the job done.
I need to draw something like this:
I was hoping that this guy posted some code of how he drew his segmented circle to begin with, but alas he didn't.
I also need to know which segment is where after interaction with the wheel - for instance if the wheel is rotated, I need to know where the original segments are after the rotation action.
Two questions:
Do I draw this segmented circle (with varying colours and content placed on the segment) with OpenGL or using Android Canvas?
Using either of the options, how do I register which segment is where?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
EDIT:
Ok, so I've figured out how to draw the segmented circle using Canvas (I'll post the code as an answer). And I'm sure I'll figure out how to rotate the circle soon. But I'm still unsure how I'll recognize a separate segment of the drawn wheel after the rotation action.
Because, what I'm thinking of doing is drawing the segmented circle with these wedges, and the sort of handling the entire Canvas as an ImageView when I want to rotate it as if it's spinning. But when the spinning stops, how do I differentiate between the original segments drawn on the Canvas?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I've read about how to draw a segment on its own (here also), OpenGL, Canvas and even drawing shapes and layering them, but I've yet to see someone explaining how to recognize the separate segments.
Can drawBitmap() or createBitmap() perhaps be used?
If I go with OpenGL, I'll probably be able to rotate the segmented wheel using OpenGL's rotation, right?
I've also read that OpenGL might be too powerful for what I'd like to do, so should I rather consider "the graphic components of a game library built on top of OpenGL"?
This kind of answers my first question above - how to draw the segmented circle using Android Canvas:
Using the code found here, I do this in the onDraw function:
// Starting values
private int startAngle = 0;
private int numberOfSegments = 11;
private int sweepAngle = 360 / numberOfSegments;
#Override
protected void onDraw(Canvas canvas) {
setUpPaint();
setUpDrawingArea();
colours = getColours();
Log.d(TAG, "Draw the segmented circle");
for (int i = 0; i < numberOfSegments; i++) {
// pick a colour that is not the previous colour
paint.setColor(colours.get(pickRandomColour()));
// Draw arc
canvas.drawArc(rectF, startAngle, sweepAngle, true, paint);
// Set variable values
startAngle -= sweepAngle;
}
}
This is how I set up the drawing area based on the device's screen size:
private void setUpDrawingArea() {
Log.d(TAG, "Set up drawing area.");
// First get the screen dimensions
Point size = new Point();
Display display = DrawArcActivity.this.getWindowManager().getDefaultDisplay();
display.getSize(size);
int width = size.x;
int height = size.y;
Log.d(TAG, "Screen size = "+width+" x "+height);
// Set up the padding
int paddingLeft = (int) DrawArcActivity.this.getResources().getDimension(R.dimen.padding_large);
int paddingTop = (int) DrawArcActivity.this.getResources().getDimension(R.dimen.padding_large);
int paddingRight = (int) DrawArcActivity.this.getResources().getDimension(R.dimen.padding_large);
int paddingBottom = (int) DrawArcActivity.this.getResources().getDimension(R.dimen.padding_large);
// Then get the left, top, right and bottom Xs and Ys for the rectangle we're going to draw in
int left = 0 + paddingLeft;
int top = 0 + paddingTop;
int right = width - paddingRight;
int bottom = width - paddingBottom;
Log.d(TAG, "Rectangle placement -> left = "+left+", top = "+top+", right = "+right+", bottom = "+bottom);
rectF = new RectF(left, top, right, bottom);
}
That (and the other functions which are pretty straight forward, so I'm not going to paste the code here) draws this:
The segments are different colours with every run.
I am developing an app which draws more or less a two-dimensional matrix of values to a canvas. The values of this matrix are scaled to Alpha levels to illustrate intensity, and the coordinates for the matrix are simply extrapolated from row and column indexes. Below is my onDraw routine.
public void onDraw(Canvas canvas, float [][] spectrum, float nsegs,int seglen) {
//canvas.translate(0,0);
//alpha = 0;
int canHeight = canvas.getHeight();
int canWidth = canvas.getWidth();
//float[] array = generateData(512);
float [] spec = new float[seglen];
final float bw = (float)(canWidth-2)/nsegs;
final float bh = (float)(canHeight-2)/(float) seglen;
for (int i = 0;i<seglen;i++){
spec[i] = spectrum[i][index]; // One column at a time
}
float max = maxVal(spec);
float min = minVal(spec);
xcoor = index;
for (int n = 0; n < seglen; n++){
//Scale value to alpha (0-255)
alpha =(int)Math.round((((spec[n] - min)/max)*255.0));
ycoor = n;
paint.setAlpha(alpha);
canvas.drawPoint(xcoor,ycoor, paint);
}
index = (int) (index +1);
if (index == nsegs-1){
index = 0;
}
}
Here paint configuration is pre-defined as:
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
paint.setStrokeWidth(2);
This program draws one pixel at a time, fills one column of pixels equal to the number of elements in a column of the matrix. Then it starts on the next column, where the previous column is still displayed and so forth. At this stage when all columns are full it stars from the first column again, drawing on top of previous elements.
The Problem: The tailing columns although already drawn appear to flicker and jump around, as does the Alpha. I have attempted to canvas.save() and canvas.restore() to capture the entire canvas and restore it after a column is printed. I have double checked all my row and column indexing and alpha vales to ensure the coordinates increment as per desired (and they do). This is very similar to the sample APIdemo DrawPoints.java, however there are three primary differences.
I am using DrawPoint not DrawPoints, and
I don't use "canvas.setColour" as it removes the tailing columns from the canvas.
This onDraw function is operating in a Thread which extends SurfaceView
Any idea's would be much appreciated, thank you for your time.
In the case above, I was using a SurfaceView instead of a View. Out of the Android dev docs
Note: On each pass you retrieve the Canvas from the SurfaceHolder, the previous state of the Canvas will be retained. In order to properly animate your graphics, you must re-paint the entire surface. For example, you can clear the previous state of the Canvas by filling in a color with drawColor() or setting a background image with drawBitmap(). Otherwise, you will see traces of the drawings you previously performed.
The Solution, re-draw the entire canvas each time to prevent the jitter.