brightening a circle in a BufferedImage?

I have my image, its the background, and i want to brighten up circles on the image, randomly placed circles (like stars), rescaleOp doesnt work because it does the whole image, (or a square if i get a subimage)

can anybody help? or give links to resources?

didn’t do anything similar but here’s an idea…
use circles as own images with transparency bit and then use brighten on them (don’t know how it effects the transparancy bit though)

To brighten an entire image:

/**	Draws a brighter version of an image.
	@param g2 the Graphics2D context to draw to
	@param image the BufferedImage to draw
	@param x the x-coordinate of the top-left corner to draw the image to
	@param y the y-coordinate of the top-left corner to draw the image to
	@param brightness the brightness level of the image.  A brightness less than 1.0 will
actually make the image darker.*/
public static void drawBrighterImage(final Graphics2D g2, final BufferedImage image,
	final int x, final int y, final float brightness)
{
	//if the image is null, don't draw it
	if(image == null)
		return;

	//compute the actual brightness
	float actualBrightness = brightness < 0.0f ? 0.0f : brightness;

	//figure out the modified brightness for every color component
	int numColors = 256;
	short[] aNewColorComponent = new short[numColors];
	for(int iColor = 0; iColor < numColors; iColor++)
		aNewColorComponent[iColor] = (short)Math.min(64.0 + actualBrightness * iColor,
			255.0);

	//put the values in a table
	short[][] aaNewColorComponentByOld;
	if(hasAlphaComponent(image)) { //if the Image has an alpha value, use a larger map
		aaNewColorComponentByOld = new short[4][];

		short[] aAlphaValue = new short[numColors];
		for(short alphaValue = 0; alphaValue < numColors; alphaValue++)
			aAlphaValue[alphaValue] = alphaValue;
		aaNewColorComponentByOld[3] = aAlphaValue;
	} else //else the Image doesn't have an alpha value, so use a smaller map
		aaNewColorComponentByOld = new short[3][];

	//put red, green, and blue component values into the table
	aaNewColorComponentByOld[0] = aaNewColorComponentByOld[1] =
		aaNewColorComponentByOld[2] = aNewColorComponent;

	//draw the Image
	LookupTable table = new ShortLookupTable(0, aaNewColorComponentByOld);
	LookupOp lookupOp = new LookupOp(table, null);
	g2.drawImage(image, lookupOp, x, y);
} //end drawBrighterImage

Perhaps, you could modify it somehow to only brighten the circles.

To selectively replace specific colors:

/**	Replaces each "old" Color in the specified BufferedImage with the corresponding "new"
Color.  The alpha value of each pixel remains unchanged.
	@param image the BufferedImage to modify
	@param aOldColor the colors to replace
	@param aNewColor the colors to replace the old colors with*/
public static void replaceColors(final BufferedImage image,
	final int[] aOldColor, final int[] aNewColor)
{
	//figure out how many colors to replace
	int cColorsToReplace = aOldColor.length;
	if(aOldColor.length != aNewColor.length) {
		cColorsToReplace = MathUtil.minimumInt(aOldColor.length, aNewColor.length);
		ErrorLog.output(null, ErrorList.imageUtilArgumentMismatchInReplaceColors,
			Arrays.toString(aOldColor), Arrays.toString(aNewColor));
	} //end if there's an argument mismatch

	//eliminate alpha values from the colors
	int alphaOnlyBitmask = 0xff000000;
	int noAlphaBitmask = 0xffffff;

	int[] aMaskedOldColor = new int[cColorsToReplace];
	for(int iColorToMask = 0; iColorToMask < cColorsToReplace; iColorToMask++)
		aMaskedOldColor[iColorToMask] = aOldColor[iColorToMask] & noAlphaBitmask;

	int[] aMaskedNewColor = new int[cColorsToReplace];
	for(int iColorToMask = 0; iColorToMask < cColorsToReplace; iColorToMask++)
		aMaskedNewColor[iColorToMask] = aNewColor[iColorToMask] & noAlphaBitmask;

	//replace the colors
	int width = image.getWidth();
	int height = image.getHeight();
	for(int x = 0; x < width; x++)
		for(int y = 0; y < height; y++) {
			int currentPixel = image.getRGB(x, y);
			int currentMaskedPixel = currentPixel & noAlphaBitmask;

			//check each color to replace
			for(int iOldColor = 0; iOldColor < aMaskedOldColor.length; iOldColor++)
				if(currentMaskedPixel == aMaskedOldColor[iOldColor]) {
					image.setRGB(x, y,
						(currentPixel & alphaOnlyBitmask) | aMaskedNewColor[iOldColor]);
					break;
				} //end if the current pixel matches one of the pixels to replace
		} //end for each row of the Image
} //end replaceColors

If the circles are a specific color, the replaceColors method should work fine.

well i dont know what color the circles will be (background color is random based on user interaction), but i just had an idea

what about creating a two dimensional array that is the size of the circle i want, and putting 0 in the positions i dont want to change and 1 in the positions i do, then request a square raster from the location on the image, run it through a filter that will change the pixels marked with a 1 to a brighter color… essentially making a circle, but scanning a square?

that good or any other idea’s out there?

p.s.

thanks for the wonderful code fletcher! sparked that idea in my head =D

Another Idea would be to make a white circle image with transparent background and use Graphics2D.drawImage to draw the image at the desired location:


Graphics2D destG2D=destinationImage.createGraphics();
destG2D.drawImage(
      circleImage,
      new LookupOp( new BitmapAdjust(1.0f, 1.0f, alpha),null ),
      circleLocationX,circleLocationY
);

You can use the alpha argument to controll the brightness level of the resulting circles. The BitmapAdjust is a class I borrowed somewhere on the net some years ago:


	public class BitmapAdjust extends LookupTable
	{
		private float mBrightness;
		private float mContrast;
		private float mAlpha;

		/**
			@param brightness Die Helligkeit des Bildes. 1.0 entspricht keiner Änderung.
			@param contrast Der Kontrast des Bildes. 1.0 entspricht keiner Änderung.
		**/
		public BitmapAdjust(float brightness, float contrast) 
		{
			super(0, 3);
			mContrast= contrast;
			mBrightness= brightness;
			mAlpha= 1.0f;
		}

		/**
			@param brightness Die Helligkeit des Bildes. 1.0 entspricht keiner Änderung.
			@param contrast Der Kontrast des Bildes. 1.0 entspricht keiner Änderung.
			@param alpha Die Transparenz des Bildes. 1.0 entspricht voller Sichtbarkeit.
		**/
		public BitmapAdjust(float brightness, float contrast, float alpha) 
		{
			super(0, 4);
			mContrast= contrast;
			mBrightness= brightness;
			mAlpha= alpha;
		}

		public int[] lookupPixel(int[] src, int[] dest)
		{
			int[] lDest= null;

			// Wenn nötig Ergebnis-Array allozieren
			if( dest != null ) lDest= dest;
			else lDest= new int[getNumComponents()];

			float lOff;
			float lValue;
			int lIndex;
			// Für alle 3 Farbkomponenten
			for(lIndex= 0; lIndex < 3; lIndex++)
			{
				// Abstand des multiplizierten Mittelpunkts
				// vom tatsächlichen Mittelpunkt berechnen
				// auf den die Helligkeit schon berechnet ist
				lOff= 128f*mContrast-128f*mBrightness;

				// Wert berechnen (Mittelpunkt der Kennlinie bleibt erhalten)
				lValue= ((float)src[lIndex]*mContrast-lOff);

				// Clipping
				if( lValue < 0 ) lDest[lIndex]= 0;
				else if( lValue > 255 ) lDest[lIndex]= 255;
				else lDest[lIndex]= (int)lValue;
			}
			if( getNumComponents() > 3 )
			{
				// Alpha berechnen
				lValue= 255f*mAlpha;
				// Clipping
				if( lValue < 0 ) lDest[3]= 0;
				else if( lValue > 255 ) lDest[3]= 255;
				else lDest[3]= (int)lValue;
			}
			// Berechneten Wert zurückgeben
			return lDest;
		}
	}

interesting cylab, didnt think about having a transparent image and doing that…

I did find a solution last night though ! =D w00t, so it works perfectly, thanks for everyones help (will post code to solution, its not refactored yet so its kinda hard to follow, but heres the solution)


//g is graphics
//img is the square circle will be in
//value the sacle is multiplied, (1 for brighter, -1 for darker)
//filter the colors if they go over 255 or under 0
public void paint(Graphics2D g){
		ImageBrightener.effectCircle(g, img, 1, true, 0, 0, 50, 50);
}
public class ImageBrightener {
public static void effectCircle(final Graphics2D g2, final BufferedImage image,
		final int value, final boolean filter, final int x, final int y, final int width, final int height){

	int[][] t = getRBGS(image, width, value, filter);
}
//scans circle finder array
//changes rbg values of image via the circlefinder array
static int[][] getRBGS(BufferedImage img, int radii, int value, boolean filter){
	
	int[][] testbythis = CircleFinder.findCircle(radii, radii);
	int[][] colors = new int[radii][radii];
	for(int x=0;x<img.getWidth();x++){
		for(int y=0;y<img.getHeight();y++){
			if(testbythis[x][y] != 0){
				int rgb = img.getRGB(x, y);
				
				int alpha = ((rgb >> 24) & 0xff); 
				int red = ((rgb >> 16) & 0xff); 
				int green = ((rgb >> 8) & 0xff); 
				 int blue = ((rgb ) & 0xff);
				    
				 	//System.out.println("Value: "+value);
				 	//System.out.println("Test: "+testbythis[x][y]);
				 	//System.out.println("Calc: "+testbythis[x][y]*value);
				 	//System.out.println("Color: "+red);
				 	//System.out.println("New C: "+(red+(testbythis[x][y]*value)));
				 	//System.out.println("Color: "+green);
				 	//System.out.println("New C: "+(green+(testbythis[x][y]*value)));
				 	//System.out.println("Color: "+blue);
				 	//System.out.println("New C: "+(blue+(testbythis[x][y]*value)));
				   
				 	
				 	red+= (testbythis[x][y] * value);
				    green+= (testbythis[x][y] * value);
				    blue+= (testbythis[x][y] * value);
				    
				    if(filter){
					    if(red > 255)
					    	red = 255;
					    if(green > 255)
					    	green = 255;
					    if(blue > 255)
					    	blue = 255;
					    if(red < 0)
					    	red = 0;
					    if(green < 0)
					    	green = 0;
					    if(blue < 0)
					    	blue = 0;
				    }
				    
				    rgb = (alpha << 24) | (red << 16) | (green << 8) | blue; 
				    
				    img.setRGB(x, y, rgb);
			}//else
				//colors[x][y] = -100;
		}
	}
	return colors;
}

//create a buffered image, draw black rect on it
//draw 5 circles different colors, giving the circle a fade effect
//scan the rbg of the new image, if the color is the blue, put the respective number in the array
//return array
public class CircleFinder {
	public static int[][] findCircle(int w, int h){
		BufferedImage bi = new BufferedImage(w, h, Transparency.BITMASK);
		Graphics2D g = bi.createGraphics();
		g.setColor(Color.BLACK);
		g.fillRect(0,0,w,h);
		//g.setColor(Color.RED);
		//g.fillOval(0,0,w,h);
		int color = 255;
		for(int i=0;i<5;i++){
			Color c = new Color(0,0,color);
			g.setColor(c);
			int x = i*2;
			int y = i*2;
			int wi = w-(i*4);
			int hi = w-(i*4);
			g.fillOval(x,y,wi,hi);
			color-=20;
		}
		//Test t = new Test(bi);
		
		int[][] p = new int[w][h];
		int multi = 1;
		for(int x=0;x<w;x++){
			for(int y=0;y<h;y++){
				int rgb = bi.getRGB(x, y);
				int red = ((rgb >> 16) & 0xff);
				int blue = ((rgb ) & 0xff);
				
				switch(blue){
				case 255:
					p[x][y] = 1;
					break;
				case 255-20:
					p[x][y] = 2;
					break;
				case 255-40:
					p[x][y] = 3;
					break;
				case 255-60:
					p[x][y] = 4;
					break;
				case 255-80:
					p[x][y] = 5;
					break;
				default:
					p[x][y] = 0;
				}
				//if(red == 255){
				//	p[x][y] = 0;
				//}else
				//	p[x][y] = 1;
			}
		}
		
		return p;
	}

Is this some form of paint program you are writing?

If so, I would suggest storing the operation to build each graphical component that the user adds - rather than the resultant pixel changes the operation causes.
It would then be trivial to change the brightness of the relevant draw operation.

Have a look at any modestly advanced paint package - they all offer a vector type manipulation mode as well as a raster based one.

Generate two images, a bright one and the normal one.

To brighten the image just add some amount to all the RGB values (clipping at 255).

Use a circular clipping area and draw the bright image on top of the dark one.

what does it mean to have a vector type manipulation mode?

and what exactly do you mean by store the operation to build the component, do you mean like, make a class that does the draw, and then store it in an array, and then call a drawSelf(Graphics2D g2d); whenever im ready to draw the thing to the picture? or something else?

sorry havnt replied sooner, busy busy with graduation hehe, tired too