Change hue scale of an imagepattern with a rectangle as container - java

I have a grayscale image, this image is set to a rectangle with an ImagePattern. like this:
ImagePattern imagePattern = new ImagePattern(new Image("File:resources/images/image.png"));
Rectangle rectangle = new Rectangle();
rectangle.setFill(imagePattern);
The only problem is I want the user to choose the colour of the image, so I want to change the hue of the image.
I found following question on StackOverflow, the first answer https://stackoverflow.com/a/18124868/15277155
shows how a coloured image is changed to a red image.
The only problem I have is that answer is done with an ImageView instead of an Imagepattern.
Is there any way This can be done with an ImagePattern.
Or that I can place the ImageView inside a rectangle?
Based on #jewelsea's comment this is the code I have.
ImagePattern imagePattern = new ImagePattern(new
Image("File:resources/images/image.png"));
Rectangle rectangle = new Rectangle();
rectangle.setFill(imagePattern);
ColorAdjust colorAdjust = new ColorAdjust();
// define target color
Color targetColor = Color.GREEN;
double hue = map( (targetColor.getHue() + 180) % 360, 0, 360, -1, 1);
colorAdjust.setHue(hue);
// use saturation as it is enter code here
double saturation = targetColor.getSaturation();
colorAdjust.setSaturation(saturation);
double brightness = map( targetColor.getBrightness(), 0, 1, -1, 0);
colorAdjust.setBrightness(brightness);
// apply color adjustment
rectangle.setEffect(colorAdjust);
rectangle.setFill(imagePattern);
I tested this on a yellow image (PNG with transparent background, but no opacity) and it worked.
Then I tried it on an image with only colors ranging from white to black (and grey) (also a PNG with transparent background, but also with opacity in the colors) and it didn't change those colors.

The ColorAdjust effect will work with any node, not just an ImageView.
So you can apply the ColorAdjust effect to your rectangle, which is filled with the ImagePattern, and the effect will be applied to the ImagePattern.

Related

Android OpenCV: color detection giving weird result

I've just learnt how to detect a color from OpenCV Java, Getting region of interest from image.
Ultimately, I want to know how can I detect the AA battery(with and or without black tape)
I'm now trying to detect the battery in the picture, but the battery is not fully black, and in turn giving me weird result:
I covered the battery with black tape and tried again the result seems better but it is detecting the battery in two separate sections:
Code:
private Bitmap findRoiBlack(Bitmap sourceBitmap) {
Bitmap roiBitmap = null;
Scalar green = new Scalar(0, 255, 0, 255);
Mat sourceMat = new Mat(sourceBitmap.getWidth(), sourceBitmap.getHeight(), CvType.CV_8UC3);
Utils.bitmapToMat(sourceBitmap, sourceMat);
Mat roiTmp = sourceMat.clone();
final Mat hsvMat = new Mat();
sourceMat.copyTo(hsvMat);
// convert mat to HSV format for Core.inRange()
Imgproc.cvtColor(hsvMat, hsvMat, Imgproc.COLOR_RGB2HSV);
Scalar lowerb = new Scalar(0, 0, 0); // lower color border for BLACK
Scalar upperb = new Scalar(180, 255, 30); // upper color border for BLACK
//Scalar lowerb = new Scalar(0, 0, 200); // lower color border for WHITE
//Scalar upperb = new Scalar(180, 255, 255); // upper color border for WHITE
Core.inRange(hsvMat, lowerb, upperb, roiTmp); // select only blue pixels
// find contours
List<MatOfPoint> contours = new ArrayList<>();
List<RotatedRect> boundingRects = new ArrayList<>();
Imgproc.findContours(roiTmp, contours, new Mat(), Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
// find appropriate bounding rectangles
for (MatOfPoint contour : contours) {
MatOfPoint2f areaPoints = new MatOfPoint2f(contour.toArray());
RotatedRect boundingRect = Imgproc.minAreaRect(areaPoints);
double rectangleArea = boundingRect.size.area();
// test min ROI area in pixels
if (rectangleArea > 400) {
Point rotated_rect_points[] = new Point[4];
boundingRect.points(rotated_rect_points);
Rect rect = Imgproc.boundingRect(new MatOfPoint(rotated_rect_points));
// test vertical ROI orientation
if (rect.height > rect.width) {
Imgproc.rectangle(sourceMat, rect.tl(), rect.br(), green, 3);
}
}
}
roiBitmap = Bitmap.createBitmap(sourceMat.cols(), sourceMat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(sourceMat, roiBitmap);
return roiBitmap;
}
Easiest way - is add color marker to battery. Other way is set solid, well distinguishable background for vertical channel of Your installation (may be even backlight - in this case You should find just black/low brightness object on white/high brightness background). If it's not possible and You have solid background - try to "invert" approach: don't try find battery (because it has many colors) - find background (because it has one solid color) - object with "non background" colors probably battery (and You have additional hints: battery is "vertical" rectangle with 1/4 proportions (AAA battery has 10.5 mm diameter and 44.6 mm length), it is approximately on the vertical center of image and has chromium-plated high brightness elements on top and bottom, etc.).

How to fade out the edges of a Java2D Area object?

I have a method that creates shadows based on where things are on the screen and the final product of that method is an Area, which I then draw onto the screen and it contains all shadows on screen in the same Area. This is because the drawn shadows are a low opacity so if it is not all one thing they will overlap and the opacity will make it look weird.
The issue that I want the shadows to look like they fade out, but I have absolutely no idea how, or if that would even be possible. Is there a way to soften the edges of the Area or make them gradient fade out? I tried to do graphics2D.setPaint(new GradientPaint[a gradient effect]) but it did nothing.
Thanks in advance
EDIT: Here is a screenshot of the program making a shadow around a 'building' rectangle. The green rectangle is to show the effect of the shadow. The end result I want is instead of the shadow abruptly ending, it should fade out.
i guess you have problems setting up the proper colors for the gradient:
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(30, 30, 50, 20);
Graphics2D g2d = (Graphics2D) g;
Polygon p = new Polygon(new int[]{10,20,50,50,40,10}, new int[]{10,10,40,50,50,20}, 6);
Area a = new Area(p);
Color b = new Color(0xFF000000, true); //using colors with transparency!!!
Color w = new Color(0x00FFFFFF, true); //using colors with transparency!!!
//try to use proper values for the x/y values - both, start and end
GradientPaint gradient = new GradientPaint(0, 0, b, 40, 40, w);
g2d.setPaint(gradient);
g2d.fill(a); // fill your area!
}
result is a gradient with alpha (Transparency) ...
Area drawn in red <==> Area drawn with Gradient
don't forget to set the alpha value 0xAARRGGBB to FF for 100% opaque (0xFF000000 is black 100%opaque) to 0 (0x00FFFFFF white, 100% transparent)

Add text with grey background to pictures like Snapchat does? Android/Java

Bitmap newBm = ...
Canvas canvas = new Canvas(newBm);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
paint.setTextSize((int) (44 * scale));
Rect bounds = new Rect();
paint.getTextBounds(gText, 0, gText.length(), bounds);
canvas.drawText(gText, x, y, paint);
I drew text on the Bitmap like so. How could I get a grey background that is the same height as the text but covers the whole screen??
You could use a Rect. Before drawing the text draw the Rect to the screen:
int screenWidth = getApplicationContext().getResources().getDisplayMetrics().widthPixels;
Rect greyBack = new Rect(0,top,screenWidth,bottom);
Paint paint = new Paint();
paint.setARGB(128, 100, 100, 100); //added alpha because Snapchat has translucent //grey background
canvas.drawRect(greyBack, paint);
top and bottom need to be coordinates above and below the text. You could use y's value and take away a bit for top and add a bit for bottom. How much you add/subtract is up to you and changes the height of the greyBack background.
The best way to see and learn how these sort of things are done with well written code is to look at the android source code itself. For example here is the onDraw method for a TextView it includes additional stuff you won't probably need like compoundPadding, but you can follow it through and get the basic concept of how it's done.

Dynamically changing the foreground color of an Image in Android Java (retaining the alpha transparency)

I have an image of red ball with transparent background. I want to change the color of ball to many other colors programatically without affecting the background i.e. background shall remain transparent. How this can be achieved in Android?
You can use the Bitmap class to modify your image in this way, such as using the setPixel() method. You just need to make sure that the color still has its alpha set to transparent.
Refer to the Color documentation here for defining colors with their RGB and Alpha channels (you want to keep the alpha values of each pixel, and only change the RGB values). Also refer to the Bitmap documentation here
Try:
//Bitmap bmp
//int color
int[] pixels = new int[bmp.getWidth() * bmp.getHeight()];
bmp.getPixels(pixels, 0, bmp.getWidth(), 0, 0,
bmp.getWidth(), bmp.getHeight());
for (int i = 0; i < pixels.length; i++) {
pixels[i] &= color;
}
Bitmap newBmp = Bitmap.createBitmap(bmp.getWidth(),
bmp.getHeight(), Config.ARGB_8888);
newBmp.setPixels(pixels, 0, newBmp.getWidth(), 0, 0, newBmp.getWidth(), newBmp.getHeight());
You can also achieve it by using Frame Animation. Use different pictures of same ball image with different ball colors, and use frame animation to run the images as frames.If so, the colors of ball looks to be changing.

java image crop

I am aware of BufferedImage.getSubimage However, it cant deal with cropping images that are smaller than the cropping size throwing the exception:
java.awt.image.RasterFormatException: (y + height) is outside raster
I want to be able to crop either a PNG/JPG/GIF to a certain size however if the image is smaller than the cropping area centre itself on a white background. Is there a call to do this? Or do I need to create an image manually to centre the image on if so, how would I go about this?
Thanks
You cannot crop an image larger, only smaller. So, you start with the goal dimension,let's say 100x100. And your BufferedImage (bi), let's say 150x50.
Create a rectangle of your goal:
Rectangle goal = new Rectangle(100, 100);
Then intersect it with the dimensions of your image:
Rectangle clip = goal.intersection(new Rectangle(bi.getWidth(), bi.getHeight());
Now, clip corresponds to the portion of bi that will fit within your goal. In this case 100 x50.
Now get the subImage using the value of clip.
BufferedImage clippedImg = bi.subImage(clip,1, clip.y, clip.width, clip.height);
Create a new BufferedImage (bi2), the size of goal:
BufferedImage bi2 = new BufferedImage(goal.width, goal.height);
Fill it with white (or whatever bg color you choose):
Graphics2D big2 = bi2.getGraphics();
big2.setColor(Color.white);
big2.fillRect(0, 0, goal.width, goal.height);
and draw the clipped image onto it.
int x = goal.width - (clip.width / 2);
int y = goal.height - (clip.height / 2);
big2.drawImage(x, y, clippedImg, null);

Categories