How to make an equal Scale for images of different resolution? - java

I wanted to convert some images to pdf
So in order to do that, I need to make pages for the image first
I will have to provide the width and height of the page and put the image on the page,
The problem is that the resolution of some images is greater than the other so the pdf does not get formed on a constant scale.
I need to make the page's scale constant without changing the resolution.
some image resolution which I tried
4160 × 3120,
720 × 1560,
466 × 400,
577 × 360,
492 × 144,
554 × 554,
I tried using this code
double ratio = (float) bitmap.getWidth() / (float) bitmap.getHeight();
double bestDelta = Double.MAX_VALUE;
int bestI = 0;
int bestJ = 0;
for (int i = 1; i < 100; i++)
{
for (int j = 1; j < 100; j++)
{
double newDelta = Math.abs ((double) i / (double) j - ratio);
if (newDelta < bestDelta)
{
bestDelta = newDelta;
bestI = i;
bestJ = j;
}
}
}
pageInfo = new PdfDocument.PageInfo.Builder(bestI, bestJ, page_no).create();
and getting the ratios but still some resolution give bigger values at some resolutions(here 466 × 400) which generates some bigger images

I'll recommend you to, use maxHeight field in you layout file.
android:maxHeight="50dp"
By this, your image cannot exceed that specified value.

Related

Is there any way to detect image is Blurry after capturing from Camera in Android (Except OpenCV )

I am working with Camera2 API and want to detect captured image is blurry or clear, i used OpenCV for this but result is not satisfactory and it increases APK size 3 times, So is there any way to detect blurry?
Measuring image focus/blur involves iterating of the pixels of the bitmap, or at least a portion thereof.
While you don't need OpenCV to iterate over the pixels of a bitmap on Android, its not for the faint of heart. Doing so in a performant way would require you to drop into JNI native code, or perhaps a technology like RenderScript, as iterating over pixels in Java or Kotlin might prove too slow.
There are many algorithms and techniques for measuring focus, or sharpness, or contrast, this is one I've used with reasonable success.
Luma is the luminosity of a pixel, i.e. grayscale pixel value. You'll want to convert each pixel to a grayscale value for this focus measure. e.g. using the NTSC formula:
pixelLuma = (red * 0.299) + (green * 0.587) + (blue * 0.114)
Here is a suggested formula to measure focus score:
FocusScore = Max({Video_Gradient}) / {Gray_Level_Dynamic_Range} * {Pixel_Pitch}
Max{Video_Gradient} = a measure of the maximum luminosity difference between adjacent pixels (x,y) across the bitmap.
e.g.:
horizontally measure pixel[x] - pixel[x+1]
vertically measure pixel[y] - pixel[y+1]
{Gray_Level_Dynamic_Range} = difference between average of N lightest pixels and N darkest pixels across the bitmap. A typical value for N is 64, in my case working on images around 1200w x 500h. Smaller images should use smaller N.
{Pixel_Pitch} = 1 / DPI = 1/200 = 0.005
This will result in a score, higher values are more in focus. You can determine a reasonable threshold.
Here is a code snippet written in C:
width = width of bitmap
height = height of bitmap
pixels = an array of bytes of size (width * height) holding pixel luminosity values
VFOCUS_N = 64
int gradientHorizontal[256];
int *pGradientHorizontal = gradientHorizontal;
int gradientVertical[256];
int *pGradientVertical = gradientVertical;
int luminanceHistogram[256];
int *pLuminance = luminanceHistogram;
int maxGradient = 0;
for (int i = 0;i < 256;i++)
{
gradientHorizontal[i] = 0;
gradientVertical[i] = 0;
luminanceHistogram[i] = 0;
}
// pixel by pixel math...
for (nRow = 0; nRow < height-1; nRow++)
{
nRowOffset = nRow * width;
nNextRowOffset = (nRow+1) * width;
for (nCol = 0; nCol < width-1; nCol++)
{
int gC = pixels[nRowOffset + nCol];
int gH = abs(gC - pixels[nRowOffset + nCol + 1]);
int gV = abs(gC - pixels[nNextRowOffset + nCol]);
pLuminance[gC]++;
pGradientHorizontal[gH]++;
pGradientVertical[gV]++;
}
}
// find max gradient
for (int i = 255;i >= 0;i--)
{
// first one with a value
if ((gradientHorizontal[i] > 0) || (gradientVertical[i] > 0))
{
maxGradient = i;
break;
}
}
// calculate dynamic range
int rangeLow = 0;
int rangeHi = 0;
int p;
p = 0;
for (int i = 0;i < 256;i++)
{
if (luminanceHistogram[i] > 0)
{
if (p + luminanceHistogram[i] > VFOCUS_N)
{
rangeLow += (i * (VFOCUS_N - p));
p = VFOCUS_N;
break;
}
p += luminanceHistogram[i];
rangeLow += (i * luminanceHistogram[i]);
}
}
if (p)
rangeLow /= p;
p = 0;
for (int i = 255;i >= 0;i--)
{
if (luminanceHistogram[i] > 0)
{
if (p + luminanceHistogram[i] > VFOCUS_N)
{
rangeHi += (i * (VFOCUS_N - p));
p = VFOCUS_N;
break;
}
p += luminanceHistogram[i];
rangeHi += (i * luminanceHistogram[i]);
}
}
if (p)
rangeHi /= p;
float mFocusScore = (float)fmin((float)maxGradient / (fabs((float)rangeHi - (float)rangeLow) * 0.005), 100.00);
Low focus scores means a blurry image. Values close to or in excess of 100 indicate a sharp image, the code above caps the score at 100.

Java geotools how to create coverage grid

How to create grid coverage when each cell is 5M ?
I found this :
GridCoverage2D coverage = reader.read(null);
// direct access
DirectPosition position = new DirectPosition2D(crs, x, y);
double[] sample = (double[]) coverage.evaluate(position); // assume double
// resample with the same array
sample = coverage.evaluate(position, sample);
Source : https://docs.geotools.org/latest/userguide/library/coverage/grid.html
I didn't found a lot of tutorial about how to create grid coverage on geotools...
To create an empty coverage you need to use the GridCoverageFactory and one of the create methods. Since you are not constructing from an existing image you need to provide some memory for your raster to be stored in (this can also hold any initial values you want). For this your choices are a float[][] or a WritableRaster. Finally, you need a Envelope to say where the coverage is and what it's resolution is (otherwise it is just an array of numbers), I favour using a ReferencedEnvelope so that I know what the units are etc, so in the example below I have used EPSG:27700 which is the OSGB national grid so I know that it is in metres and I can define the origin somewhere in the South Downs. By specifying the lower left X and Y coordinates and the upper right X and Y as resolution times the width and height (plus the lower left corner) the maths all works out to make sure that the size of my pixels is resolution.
So keeping it simple for now you could do something like:
float[][] data;
int width = 100;
int height = 200;
data = new float[width][height];
int resolution = 5;
for(int i=0;i<width;i++){
for(int j=0;j<height;j++ ){
data[i][j] = 0.0f;
}
}
GridCoverageFactory gcf = new GridCoverageFactory();
CoordinateReferenceSystem crs = CRS.decode("EPSG:27700");
int llx = 500000;
int lly = 105000;
ReferencedEnvelope referencedEnvelope = new ReferencedEnvelope(llx, llx + (width * resolution), lly, lly + (height * resolution),
crs);
GridCoverage2D gc = gcf.create("name", data, referencedEnvelope);
If you want more bands in your coverage then you need to use a WriteableRaster as the base for your coverage.
WritableRaster raster2 = RasterFactory.createBandedRaster(java.awt.image.DataBuffer.TYPE_INT, width,
height, 3, null);
for (int i = 0; i < width; i++) {//width...
for (int j = 0; j < height; j++) {
raster2.setSample(i, j, 0, rn.nextInt(200));
raster2.setSample(i, j, 1, rn.nextInt(200));
raster2.setSample(i, j, 2, rn.nextInt(200));
}
}

Rounding up to the nearest 4 (simple math)

I am REALLY bad at math and have been trying to figure this out for quite a while but its all guesswork really.
I have a grid that is filled with X boxes. 4 boxes can fit horizontally along the grid. For every multiple of 4 boxes +1, the grid needs to expand vertically to fit a new row of boxes in.
Each box is 300 units deep/in height.
So say I have 4 boxes, the grid needs to be 300 units deep.
If I have 5 boxes it needs to be 600 units deep.
If I have 8 boxes it needs to be 600 units deep.
If I have 9 boxes it needs to be 900 units deep.
If I have 14 boxes it needs to be 1200 units deep.
Here is my mostly commented code trying to figure this out by Googling for people's solutions to rounding up.
The closest I am at the moment is:
height of grid = numberofentries rounded up to the nearest 4, divided by 4, times 300px
Thankyou for reading. I am shit at math. Below is my random commented stuff and someones function that may or may not be needed (there are plenty of math functions on Google but I just don't know what I'm doing)
//Integer totalHeight= 300*((Math.round(imageURLs.size()/6)));
//Integer totalHeight = imageURLs.size()*300/4;
Integer totalHeight = (roundUp(imageURLs.size(), 4)) / 4 * 300;
// height = numberofentries / 4 rounded up to the nearest multiple of 4
// height = numberofentries rounded up to the nearest 4, divided by 4, times 300px
//Double heightMath= 300*(4*(Math.ceil(Math.abs(imageURLs.size()/4))));
//Long heightMath= 300*(long)Math.floor(imageURLs.size() + 1d);
//Integer totalHeight = (int) (double) heightMath;
int roundUp (int numToRound, int multiple) {
if (multiple == 0) {
return numToRound;
}
int remainder = numToRound % multiple;
if (remainder == 0) {
return numToRound;
}
return numToRound + multiple - remainder;
}
I don't even know if I'm supposed to be "rounding". It could be some other math term... PS this is not homework, its for functionality in my project that composites images to a single image ...just they need formatting
Here is the full code and the output image from the http://imgur.com/39BgxkL (warning 2mb image)
public class testImage {
//int roundUp(int numToRound, int multiple)
//{
// if(multiple == 0)
// {
// return numToRound;
// }
//
// int remainder = numToRound % multiple;
// if (remainder == 0)
// return numToRound;
// return numToRound + multiple - remainder;
//}
int roundUp(int numToRound, int multiple) {
return (numToRound+multiple-1) / multiple;
}
public testImage() throws IOException
{
ArrayList <String> imageURLs = new ArrayList<>();
imageURLs.add("C:\\Users\\J\\Desktop\\test1.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test2.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test3.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test4.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test5.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test6.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test7.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test1.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test2.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test3.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test4.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test5.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test6.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test7.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test7.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test6.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test7.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test1.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test2.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test3.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test4.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test5.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test6.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test7.jpg");
//Integer totalHeight= 300*((Math.round(imageURLs.size()/6)));
//Integer totalHeight = imageURLs.size()*300/4;
//Integer totalHeight = 300*(roundUp(imageURLs.size(), 4));
//Integer totalHeight = (roundUp(imageURLs.size(),4))/4*300;
// height = numberofentries / 4 rounded up to the nearest multiple of 4
// height = numberofentries rounded up to the nearest 4, divided by 4, times 300px
Double heightMath= 300*(4*(Math.ceil(Math.abs(imageURLs.size()/4.0))));
//Long heightMath= 300*(long)Math.floor(imageURLs.size() + 1d);
Integer totalHeight = (int) (double) heightMath;
if (totalHeight < 300){
totalHeight = 300;
}
BufferedImage result = new BufferedImage(
864, totalHeight, //work these out
BufferedImage.TYPE_INT_RGB);
Graphics g = result.getGraphics();
Integer x = 0;
Integer y = 0;
for(String imageURL : imageURLs){
BufferedImage bi = ImageIO.read(new File(imageURL));
g.drawImage(bi, x, y, null);
x += 216;
if(x > result.getWidth()){
x = 0;
y += bi.getHeight();
}
ImageIO.write(result,"png",new File("C:\\Users\\J\\Desktop\\resultimage.jpg"));
}
The common trick to round the division by N is to add N-1, and divide in integers:
int roundUp(int numToRound, int multiple) {
return (numToRound+multiple-1) / multiple;
}
This assumes that multiple is not zero.
Sorry to put you through all this. I discovered that the dimensions of the test images I was using is actually 200 instead of the 300 that I had stretched them to on my html pages. This caused the big gap in the image composite and made me think the formulas weren't working.
I also found that I had to change values in the rest of the code to compensate for this, as images were missing off the screen.
Thanks for your help everyone.
A screenshot shows it working: http://i.imgur.com/vAiakfQ.jpg
The working code is:
public class testImage {
int roundUp(int numToRound, int multiple) {
return (numToRound+multiple-1) / multiple;
}
public testImage() throws IOException
{
ArrayList <String> imageURLs = new ArrayList<>();
imageURLs.add("C:\\Users\\J\\Desktop\\test5.jpg");
imageURLs.add("C:\\Users\\J\\Desktop\\test5.jpg");
Integer totalHeight = (roundUp(imageURLs.size(),4))*200;
System.out.println(imageURLs.size());
System.out.println(totalHeight);
BufferedImage result = new BufferedImage(
736, totalHeight, //work these out
BufferedImage.TYPE_INT_RGB);
Graphics g = result.getGraphics();
Integer x = 0;
Integer y = 0;
for(String imageURL : imageURLs){
BufferedImage bi = ImageIO.read(new File(imageURL));
g.drawImage(bi, x, y, null);
x += 184;
if(x >= result.getWidth()){
x = 0;
y += bi.getHeight();
}
ImageIO.write(result,"png",new File("C:\\Users\\J\\Desktop\\resultimage.jpg"));
}
}
}

Algorithm to find neighboring subimages

I have an image and I am extracting a subimage to feed to my neural network. I am attempting to calculate the average output of all the subimages in that same neighborhood.
So if I have an original image (m X n pixels) and I found a subimage at (sub_x, sub_y) with size (sub_width and sub_height), I also need to extract subimages with the same size (sub_width and sub_height) at (sub_x + m, sub_y + n) where m and n go from 1 - 3.
I already have a working solution:
for (int subX = (x-3); subX < (x+4); subX++)
for (int subY = (y-3); subY < (y+4); subY++)
if ( (subX > 0) && (subY > 0) )
if ( ((subX + width) < img.getWidth()) && ((subY + height) < img.getHeight()) ){
counter++;
testingImage = img.getSubimage(subX, subY, width, height);
}
x,y, width, and height are all integers of the original subimage I found.
img is the original full sized BufferedImage.
I'm not too happy about the performance though. Is there a faster/smarter way to do this?
Here's one simple thing you can do: get rid of those conditions inside loops. Calculate your ranges first, just once and then run the loops without range checks.
int subXStart = max(x-3, 0);
int subYStart = max(y-3, 0);
int subXEnd = min(x+4, img.getWidth() - width);
int subYEnd = min(y+4, img.getHeight() - height);
for (int subX = subXStart; subX < subXEnd; subX++) {
for (int subY = subYStart; subY < subYEnd; subY++) {
counter++;
testingImage = img.getSubimage(subX, subY, width, height);
// run your neural net
}
}
You can also try switching the order of loops. The order that matches the memory ordering should be considerably faster.

Gradient color lookup in Java

I have a list of values from 0-1. I want to convert this list to an image by using a gradient that converts these floating point values to RGB values. Are there any tools in Java that provide you with this functionality?
0 should be mapped 0
1 should be mapped 255
keep in mind that you need 3 of them to make a color
so multiply by 255 the floating number and cast it to int.
Perhaps GradientPaint can do what you want. It's unclear how you want a list of floating point values to be converted into a gradient. Normally a gradient consists of two colors and some mechanism that interpolates between those colors. GradientPaint implements a linear gradient.
Say you have an array made of 64 000 triples corresponding to RGB values, like this:
final Random rand = new Random();
final float[] f = new float[320*200*3];
for (int i = 0; i < f.length; i++) {
f[i] = rand.nextFloat(); // <-- generates a float between [0...1.0[
}
And say you have a BufferedImage that has a size of 320x200 (64 000 pixels) of type INT_ARGB (8 bits per value + 8 bits for the alpha level):
final BufferedImage bi = new BufferedImage( 320, 200, BufferedImage.TYPE_INT_ARGB );
Then you can convert you float array to RGB value and fill the image doing this:
for (int x = 0; x < 320; x++) {
for (int y = 0; y < 200; y++) {
final int r = (int) (f[x+y*200*3] * 255.0);
final int g = (int) (f[x+y*200*3+1] * 255.0);
final int b = (int) (f[x+y*200*3+2] * 255.0);
bi.setRGB( x, y, 0xFF000000 | (r << 16) | (g << 8) | b );
}
}
Note that would you display this image it would appear gray but if you zoom in it you'll see it's actually made of perfectly random colorful pixels. It's just that the random number generator is so good that it all looks gray on screen :)

Categories