How to integrate confidence values into DNA chromatogram images? - java

I'm using biojava to create a chromatogram.
The chromatogram is an image. Each basecall is held within a rectange.
To get x coordinate (left side): gfx.getCallboxBounds(int i).getX();
To get width: gfx.getCallboxBounds(int i).getX()
where the integer i represents the rectangle in the arrangement of rectangles that build the chromatogram.
To get the confidence value of a given base:
(I create an array called confidence) confidence[i - 1];
where i is, again, the base in question.
Confidence values are reported between 1 and 70. The height of the image is 240 pixels.
I want to print 2 pixel thick, gray lines at relatives heights along the sequence, for the width of each basecall.
For instance, if the quality of basecall (Rectangle) 60 is 40 and its width is 20, a gray line will be drawn at 137 pixels (40 / 70 * 240) for its width.
Here is the method that draws the trace:
ChromatogramFactory chromFactory = new ChromatogramFactory();
Chromatogram chrom = ChromatogramFactory.create(abi);
ChromatogramGraphic gfx = new ChromatogramGraphic(chrom);
BufferedImage bi = new BufferedImage(
gfx.getWidth(),
gfx.getHeight(),
BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = bi.createGraphics();
g2.setBackground(Color.white);
g2.clearRect(0, 0, bi.getWidth(), bi.getHeight());
if (g2.getClip() == null) {
g2.setClip(new Rectangle(0, 0, bi.getWidth(), bi.getHeight()));
}
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
gfx.drawTo(g2);
g2.draw(new java.awt.Rectangle(-10, -10, 5, 5));
EDIT: Also, the sequence length is the same as the number of rectangles. Each letter in the sequence represents a basecall, as does each rectangle.

Using the code below, I was able to add lines at relative locations to give the confidence values:
int leftBound = 0;
int rightBound = 0;
double confVal = 0;
double heightDouble = 0;
int height = 0;
g2.setColor(Color.LIGHT_GRAY);
for (int i = 0; i < gfx.getCallboxCount(); i++) {
leftBound = (int) gfx.getCallboxBounds(i).getX();
rightBound = (int) ((int) leftBound + gfx.getCallboxBounds(i).getWidth());
confVal = confidence[i] * 2.67;
heightDouble = 200 - confVal;
height = (int) heightDouble;
g2.drawLine(leftBound, height, rightBound, height);
}

Related

Java: dynamically create a png image from BufferedImage

I want to dynamically create an image, and the created image must meet some requirements.
The created image should be a png, and it must have the same behavior as if it's a loaded png from a file.
It's for creating a texture to use in LWJGL.
When I load a png image as a file and have a BufferedImage, I can use the following code for my texture:
(The Texture constructor is designed for using with loaded images)
public class Texture {
public Texture(BufferedImage bi) {
width = bi.getWidth();
height = bi.getHeight();
System.out.println(bi.toString());
int[] pixels_raw = new int[width * height];
pixels_raw = bi.getRGB(0, 0, width, height, null, 0, width);
ByteBuffer pixels = BufferUtils.createByteBuffer(width * height * 4);
for(int i = 0; i < width; i++) {
for(int j = 0; j < height; j++) {
int pixel = pixels_raw[i * width + j]; // This is the error line.
pixels.put((byte)((pixel >> 16) & 0xFF)); // red
pixels.put((byte)((pixel >> 8) & 0xFF)); // green
pixels.put((byte)(pixel & 0xFF)); // blue
pixels.put((byte)((pixel >> 24) & 0xFF)); // alpha
}
}
pixels.flip();
id = glGenTextures();
glBindTexture(GL_TEXTURE_2D, id);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
}
}
But when I try to create an image dynamically, without loading anything from a file, then I get an ArrayIndexOutOfBoundsException on line 18 of the above code (see comment in code).
Of course it has something to do with the bits per pixel of the created BufferedImage. I tried changing the image type for my BufferedImage, and changing the array size when initializing the pixels_raw array. But I still get array exceptions. So, the above constructor method does only works when I pass a BufferedImage instance which comes from a loaded png. When I pass in a BurfferedImage I created dynamically with the code below, it gives me the exceptions I mentioned before.
public class TextDrawer {
public BufferedImage drawText(String text, Font font, Color color) {
BufferedImage graphicsGetterBi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics g = graphicsGetterBi.getGraphics();
Graphics2D g2 = (Graphics2D) g;
Rectangle2D bounds = font.getStringBounds(text, 0, text.length(), g2.getFontRenderContext());
BufferedImage bi = new BufferedImage((int) bounds.getWidth(), (int) bounds.getHeight(), BufferedImage.TYPE_INT_ARGB);
System.out.println("Created the image. \n");
g2.setColor(color);
g2.setFont(font);
g2.drawString(text, 0, 0);
return bi;
}
}
instead of int pixel = pixels_raw[i * width + j]; it should be int pixel = pixels_raw[i * height + j]; or int pixel = pixels_raw[j * width + i];. Consider you have image of width = 2x and height = x. Then the array size is 2x^2, while the maximum index you request for is (2x - 1) * 2x + x - 1 = 4x^2 - x - 1, which is more than 2x^2 for x > 2

Rendering an isometric grid

I'm making a map editor for an isometric game, and I'm a bit stuck on rendering an isometric guide grid (a grid that shows where objects will be placed). That is, I need to draw lines across a Graphics object in such a way that it forms a grid with cells of variable width and height. What can I do to accomplish this?
So far I have:
//The number of cells in each direction
int nv=h/cellh;
int nh=w/cellw;
for(int i=1;i<=nv;++i){
g.drawLine(0,i*cellh,i*cellh*2,0);
}
But that just draws bottom left to upper right lines that begin on the left side.
This will work as you expect:
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
int width = getWidth();
int height = getHeight();
int sizeW = 50;
int sizeH = 50;
int countW = width / sizeW;
int countH = height / sizeH;
for (int i = 0; i <= countW + countH; i++) {
g.drawLine(0, i * sizeH, i * sizeH, 0);
g.drawLine(width - i * sizeW, 0, width, i * sizeW);
}
}

How to remove a border with an unknown width from an image

I'm trying to build a program which can remove an single-colored border form an image.
The border is always white but the width of the border on the left and right side might differ from the width of the border at the top and bottom. So the image I want to extract is centered within the source image.
So from the following image I want to extract the green rectangle.
At the moment I don't know how to start solving this problem.
UPDATE
So finally calsign's code snippet and some improvements on it, solves my problem. I realized that the border around the inner image may not be completely single colored but can vary slightly. This leads to the behavior that for some images were left with a small border.
I solved this problem by improving the comparison of the color of two pixels by comparing the color distance of the two colors with a threshold. When the distance is below the threshold then the colors are handled as equally.
public Bitmap cropBorderFromBitmap(Bitmap bmp) {
//Convenience variables
int width = bmp.getWidth();
int height = bmp.getHeight();
int[] pixels = new int[height * width];
//Load the pixel data into the pixels array
bmp.getPixels(pixels, 0, width, 0, 0, width, height);
int length = pixels.length;
int borderColor = pixels[0];
//Locate the start of the border
int borderStart = 0;
for(int i = 0; i < length; i ++) {
// 1. Compare the color of two pixels whether they differ
// 2. Check whether the difference is significant
if(pixels[i] != borderColor && !sameColor(borderColor, pixels[i])) {
Log.i(TAG,"Current Color: " + pixels[i]);
borderStart = i;
break;
}
}
//Locate the end of the border
int borderEnd = 0;
for(int i = length - 1; i >= 0; i --) {
if(pixels[i] != borderColor && !sameColor(borderColor, pixels[i])) {
Log.i(TAG,"Current Color: " + pixels[i]);
borderEnd = length - i;
break;
}
}
//Calculate the margins
int leftMargin = borderStart % width;
int rightMargin = borderEnd % width;
int topMargin = borderStart / width;
int bottomMargin = borderEnd / width;
//Create the new, cropped version of the Bitmap
bmp = Bitmap.createBitmap(bmp, leftMargin, topMargin, width - leftMargin - rightMargin, height - topMargin - bottomMargin);
return bmp;
}
private boolean sameColor(int color1, int color2){
// Split colors into RGB values
long r1 = (color1)&0xFF;
long g1 = (color1 >>8)&0xFF;
long b1 = (color1 >>16)&0xFF;
long r2 = (color2)&0xFF;
long g2 = (color2 >>8)&0xFF;
long b2 = (color2 >>16)&0xFF;
long dist = (r2 - r1) * (r2 - r1) + (g2 - g1) * (g2 - g1) + (b2 - b1) *(b2 - b1);
// Check vs. threshold
return dist < 200;
}
Perhaps not the best use of the APIs to find a solution, but the one that came to mind: directly modify the image's pixels.
You can get a Bitmap's pixels with getPixels() and then create a new, cropped Bitmap with createBitmap(). Then, it's just a matter of finding the dimensions of the border.
You can find the color of the border by accessing the pixel located at position 0, and then compare that value (an int) to the value of each proceeding pixel until your reach the border (the pixel that isn't that color). With a little bit of math, it can be done.
Here is some simple code that demonstrates the point:
private void cropBorderFromBitmap(Bitmap bmp) {
int[] pixels;
//Load the pixel data into the pixels array
bmp.getPixels(pixels, 0, width, 0, 0, width, height);
//Convenience variables
int width = bmp.getWidth();
int height = bmp.getHeight();
int length = pixels.length;
int borderColor = pixels[0];
//Locate the start of the border
int borderStart;
for(int i = 0; i < length; i ++) {
if(pixels[i] != borderColor) {
borderStart = i;
break;
}
}
//Locate the end of the border
int borderEnd;
for(int i = length - 1; i >= 0; i --) {
if(pixels[i] != borderColor) {
borderEnd = length - i;
break;
}
}
//Calculate the margins
int leftMargin = borderStart % width;
int rightMargin = borderEnd % width;
int topMargin = borderStart / width;
int bottomMargin = borderEnd / width;
//Create the new, cropped version of the Bitmap
bmp = createBitmap(bmp, leftMargin, topMargin, width - leftMargin - rightMargin, height - topMargin - bottomMargin);
}
This is untested and lacks error checking (e.g., what if the width is 0?), but it should serve as a proof-of-concept.
EDIT: I just realized that I failed to complete the getPixels() method. The wonders of testing your code... it's fixed now.
If the frame around your picture is uniform then all you need to do is investigate when the pixels in the image change.
But first thing's first - you need to have a BufferedImage object to work with. It's a class that allows you to traverse the bitmap of an image (http://docs.oracle.com/javase/6/docs/api/java/awt/image/BufferedImage.html).
If you have the image saved as a file you need to call this method:
BufferedImage bimage = ImageIO.read(new File(file));
Now you can fetch the bitmap array from the bimage:
bimage.getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize)
like this:
int[] rgb = bimage.getRGB(0, 0, bimage.getWidth(), bimage.getHeight(), null, 0, bimage.getWidth());
There could be some issues here with ColorModel so be sure to read up on your documentation of how to fetch the appropriate rgb from different file types.
Now that you have the rgb array you should start searching how far the frame stretches out from the middle of the picture. Keep in mind that this a single dimensional array - all the lines are written here sequentially one after another - as if you sliced the picture into lines 1pixel heigh and glued them together to form one long line.
This actually works to our advantage because the first different pixel we encounter in this table will work as a great reference point.
So now we just do something like this:
int pixel1=0,pixel2=0, i=0;
while(pixel1==pixel2 && i<bimage.getWidth()*bimage.getHeight()){
pixel1=pixel2;
pixel2=rgb[i++];
}
So now if the frame of your image is uniform, the top offset is the same as the bottom offset and the left offset is the same as the right offset then the number in the variable i is very likely to be the first pixel in the green rectangle.
In order to know which row and which column it is you need the following code:
int row= i%bimage.getWidth();
int column= i - row*bimage.getWidth();
Now the problem is that you may have an image embedded in the frame that in it's left upper corner is of the same color as the frame - so for example an image of a green rectangle with white corners in a white frame. Is this the case?
You can use the public int getPixel (int x, int y) function which return for every pixel its color
It should be easy to run through the border lines and verify that the color is still the same
This is my solution:
private Bitmap cropBorderFromBitmap(Bitmap bmp) {
final int borderWidth = 10; //preserved border width
final int borderColor = -1; //WHITE
int width = bmp.getWidth();
int height = bmp.getHeight();
int[] pixels = new int[width * height];
bmp.getPixels(pixels, 0, width, 0, 0, width, height);
int minX = -1;
int minY = -1;
int maxX = -1;
int maxY = -1;
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
if(bmp.getPixel(x,y) != borderColor) {
minX = (minX == -1) ? x : Math.min(x, minX);
minY = (minY == -1) ? y : Math.min(y, minY);
maxX = (maxX == -1) ? x : Math.max(x, maxX);
maxY = (maxY == -1) ? y : Math.max(y, maxY);
}
}
}
minX = Math.max(0, minX - borderWidth);
maxX = Math.min(width, maxX + borderWidth);
minY = Math.max(0, minY - borderWidth);
maxY = Math.min(height, maxY + borderWidth);
//Create the new, cropped version of the Bitmap
return Bitmap.createBitmap(bmp, minX, minY, maxX - minX, maxY-minY);
}

Resizing an image in swing

I have snippet of code that I am using for the purpose of resizing an image to a curtain size (I want to change the resolution to something like 200 dpi). Basically the reason I need it is because I want to display the image that the user have picked (somewhat large) and then if the user approves I want to display the same image in a different place but using a smaller resolution. Unfortunately, if I give it a large image nothing appears on the screen. Also, if I change
imageLabel.setIcon(newIcon);
to
imageLabel.setIcon(icon);
I get the image to display but not in the correct resolution that's how I know that I have a problem inside this snipper of code and not somewhere else.
Image img = icon.getImage();
BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
BufferedImage bi = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics();
boolean myBool = g.drawImage(img, 0, 0, 100, 100, null);
System.out.println(myBool);
ImageIcon newIcon = new ImageIcon(bi);
imageLabel.setIcon(newIcon);
submitText.setText(currentImagePath);
imageThirdPanel.add(imageLabel);
You don't really have to care about the details of scaling images. The Image class has already a method getScaledInstance(int width, int height, int hints) designed for this purpose.
Java documentation says:
Creates a scaled version of this image. A new Image object is returned
which will render the image at the specified width and height by
default. The new Image object may be loaded asynchronously even if the
original source image has already been loaded completely. If either
the width or height is a negative number then a value is substituted
to maintain the aspect ratio of the original image dimensions.
And you can use it like this:
// Scale Down the original image fast
Image scaledImage = imageToScale.getScaledInstance(newWidth, newHighth, Image.SCALE_FAST);
// Repaint this component
repaint();
Check this for a complete example.
Here is my solution:
private BufferedImage resizeImage(BufferedImage originalImage, int width, int height, int type) throws IOException {
BufferedImage resizedImage = new BufferedImage(width, height, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, width, height, null);
g.dispose();
return resizedImage;
}
Try this CODE to resize image :
public static Image scaleImage(Image original, int newWidth, int newHeight) {
//do nothing if new and old resolutions are same
if (original.getWidth() == newWidth && original.getHeight() == newHeight) {
return original;
}
int[] rawInput = new int[original.getHeight() * original.getWidth()];
original.getRGB(rawInput, 0, original.getWidth(), 0, 0, original.getWidth(), original.getHeight());
int[] rawOutput = new int[newWidth * newHeight];
// YD compensates for the x loop by subtracting the width back out
int YD = (original.getHeight() / newHeight) * original.getWidth() - original.getWidth();
int YR = original.getHeight() % newHeight;
int XD = original.getWidth() / newWidth;
int XR = original.getWidth() % newWidth;
int outOffset = 0;
int inOffset = 0;
for (int y = newHeight, YE = 0; y > 0; y--) {
for (int x = newWidth, XE = 0; x > 0; x--) {
rawOutput[outOffset++] = rawInput[inOffset];
inOffset += XD;
XE += XR;
if (XE >= newWidth) {
XE -= newWidth;
inOffset++;
}
}
inOffset += YD;
YE += YR;
if (YE >= newHeight) {
YE -= newHeight;
inOffset += original.getWidth();
}
}
return Image.createRGBImage(rawOutput, newWidth, newHeight, false);
}
Another example is given here :
2D-Graphics/LoadImageandscaleit.htm">http://www.java2s.com/Tutorial/Java/0261_2D-Graphics/LoadImageandscaleit.htm
http://www.java2s.com/Code/JavaAPI/java.awt/ImagegetScaledInstanceintwidthintheightinthints.htm

Set BufferedImage alpha mask in Java

I have two BufferedImages I loaded in from pngs. The first contains an image, the second an alpha mask for the image.
I want to create a combined image from the two, by applying the alpha mask. My google-fu fails me.
I know how to load/save the images, I just need the bit where I go from two BufferedImages to one BufferedImage with the right alpha channel.
I'm too late with this answer, but maybe it is of use for someone anyway. This is a simpler and more efficient version of Michael Myers' method:
public void applyGrayscaleMaskToAlpha(BufferedImage image, BufferedImage mask)
{
int width = image.getWidth();
int height = image.getHeight();
int[] imagePixels = image.getRGB(0, 0, width, height, null, 0, width);
int[] maskPixels = mask.getRGB(0, 0, width, height, null, 0, width);
for (int i = 0; i < imagePixels.length; i++)
{
int color = imagePixels[i] & 0x00ffffff; // Mask preexisting alpha
int alpha = maskPixels[i] << 24; // Shift blue to alpha
imagePixels[i] = color | alpha;
}
image.setRGB(0, 0, width, height, imagePixels, 0, width);
}
It reads all the pixels into an array at the beginning, thus requiring only one for-loop. Also, it directly shifts the blue byte to the alpha (of the mask color), instead of first masking the red byte and then shifting it.
Like the other methods, it assumes both images have the same dimensions.
I played recently a bit with this stuff, to display an image over another one, and to fade an image to gray.
Also masking an image with a mask with transparency (my previous version of this message!).
I took my little test program and tweaked it a bit to get the wanted result.
Here are the relevant bits:
TestMask() throws IOException
{
m_images = new BufferedImage[3];
m_images[0] = ImageIO.read(new File("E:/Documents/images/map.png"));
m_images[1] = ImageIO.read(new File("E:/Documents/images/mapMask3.png"));
Image transpImg = TransformGrayToTransparency(m_images[1]);
m_images[2] = ApplyTransparency(m_images[0], transpImg);
}
private Image TransformGrayToTransparency(BufferedImage image)
{
ImageFilter filter = new RGBImageFilter()
{
public final int filterRGB(int x, int y, int rgb)
{
return (rgb << 8) & 0xFF000000;
}
};
ImageProducer ip = new FilteredImageSource(image.getSource(), filter);
return Toolkit.getDefaultToolkit().createImage(ip);
}
private BufferedImage ApplyTransparency(BufferedImage image, Image mask)
{
BufferedImage dest = new BufferedImage(
image.getWidth(), image.getHeight(),
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = dest.createGraphics();
g2.drawImage(image, 0, 0, null);
AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.DST_IN, 1.0F);
g2.setComposite(ac);
g2.drawImage(mask, 0, 0, null);
g2.dispose();
return dest;
}
The remainder just display the images in a little Swing panel.
Note that the mask image is gray levels, black becoming full transparency, white becoming full opaque.
Although you have resolved your problem, I though I could share my take on it. It uses a slightly more Java-ish method, using standard classes to process/filter images.
Actually, my method uses a bit more memory (making an additional image) and I am not sure it is faster (measuring respective performances could be interesting), but it is slightly more abstract.
At least, you have choice! :-)
Your solution could be improved by fetching the RGB data more than one pixel at a time(see http://java.sun.com/javase/6/docs/api/java/awt/image/BufferedImage.html), and by not creating three Color objects on every iteration of the inner loop.
final int width = image.getWidth();
int[] imgData = new int[width];
int[] maskData = new int[width];
for (int y = 0; y < image.getHeight(); y++) {
// fetch a line of data from each image
image.getRGB(0, y, width, 1, imgData, 0, 1);
mask.getRGB(0, y, width, 1, maskData, 0, 1);
// apply the mask
for (int x = 0; x < width; x++) {
int color = imgData[x] & 0x00FFFFFF; // mask away any alpha present
int maskColor = (maskData[x] & 0x00FF0000) << 8; // shift red into alpha bits
color |= maskColor;
imgData[x] = color;
}
// replace the data
image.setRGB(0, y, width, 1, imgData, 0, 1);
}
For those who are using alpha in the original image.
I wrote this code in Koltin, the key point here is that if you have the alpha on your original image you need to multiply these channels.
Koltin Version:
val width = this.width
val imgData = IntArray(width)
val maskData = IntArray(width)
for(y in 0..(this.height - 1)) {
this.getRGB(0, y, width, 1, imgData, 0, 1)
mask.getRGB(0, y, width, 1, maskData, 0, 1)
for (x in 0..(this.width - 1)) {
val maskAlpha = (maskData[x] and 0x000000FF)/ 255f
val imageAlpha = ((imgData[x] shr 24) and 0x000000FF) / 255f
val rgb = imgData[x] and 0x00FFFFFF
val alpha = ((maskAlpha * imageAlpha) * 255).toInt() shl 24
imgData[x] = rgb or alpha
}
this.setRGB(0, y, width, 1, imgData, 0, 1)
}
Java version (just translated from Kotlin)
int width = image.getWidth();
int[] imgData = new int[width];
int[] maskData = new int[width];
for (int y = 0; y < image.getHeight(); y ++) {
image.getRGB(0, y, width, 1, imgData, 0, 1);
mask.getRGB(0, y, width, 1, maskData, 0, 1);
for (int x = 0; x < image.getWidth(); x ++) {
//Normalize (0 - 1)
float maskAlpha = (maskData[x] & 0x000000FF)/ 255f;
float imageAlpha = ((imgData[x] >> 24) & 0x000000FF) / 255f;
//Image without alpha channel
int rgb = imgData[x] & 0x00FFFFFF;
//Multiplied alpha
int alpha = ((int) ((maskAlpha * imageAlpha) * 255)) << 24;
//Add alpha to image
imgData[x] = rgb | alpha;
}
image.setRGB(0, y, width, 1, imgData, 0, 1);
}
Actually, I've figured it out. This is probably not a fast way of doing it, but it works:
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
Color c = new Color(image.getRGB(x, y));
Color maskC = new Color(mask.getRGB(x, y));
Color maskedColor = new Color(c.getRed(), c.getGreen(), c.getBlue(),
maskC.getRed());
resultImg.setRGB(x, y, maskedColor.getRGB());
}
}

Categories

Resources