KMeans clustering of RGB image using OpenCV in Java - java

I've been working on this snippet:
public static final TermCriteria KMEANS_CRITERIA = new TermCriteria(TermCriteria.EPS + TermCriteria.MAX_ITER, 10, 1.0);
private double getColours(Mat image) {
var labels = new MatOfFloat();
var reshape = new Mat();
image.convertTo(reshape, CvType.CV_32FC3);
reshape = reshape.reshape(1,1);
System.out.println("reshape = " + reshape.toString());
var centers = new Mat();
Core.kmeans(reshape, 3, labels, KMEANS_CRITERIA, 3, Core.KMEANS_RANDOM_CENTERS, centers);
}
The problem is, reshape = reshape.reshape(1,1); converts the image from CV_32FC3[X, Y] to CV_32FC1[X*Y] - it goes from 3 channels (R,G,B) to 1 channel.
I think this is the final problem to solve, in order to get the KMeans clustering working.
Anyone know how to fix this, so that I can get a final result of centers = CV_8UC3[3] (the 3 colour clusters)

Related

How to set the registration point of a Bitmap image to the bottom centre?

I am trying to set the registration point of an image to the bottom centre so it can rotate around that point. So far my code looks like this:
var img = new createjs.Bitmap("img.png");
img.x = 200;
img.y = 180;
img.scaleX = 0.35;
img.scaleY = 0.35;
img.regX = img.width/2;
img.regY = 0;
img.rotation = 15;
canvas.addChild(img);
I tried changing the numbers of img.regY but I can't seem to get it correct.
What is redBalloon.width?
The best approach is to wait until the image is loaded, and then use its natural width.
img.image.onload = function() {
img.regX = img.image.naturalWidth;
img.regY = img.image.naturalHeight;
}
Hope that helps.

URLImage in InfiniteScrollAdapter in Simulator shows NPE (CodenameOne)

My app features an InfiniteScrollAdapter populated with images through URLImage and URLImage.ImageAdapter.
In the simulator (Iphone3GS or Xoom or GoogleNexus7), and NPE is shown the first time the InfiniteScrollAdapter appears, although the file does exist on the server.
Please note : In this test there was only one entry in the database. So on the image below what you should see is the same row (image + text) duplicated 3 times.
Please note that the order in the undisplayed icon can differ
The code I used to download the image is :
Image tempPlaceholder = Image.createImage(
ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX,
ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX,
ParametresGeneraux.accentColor);
Graphics gr = tempPlaceholder.getGraphics();
gr.setAntiAliased(true);
gr.setColor(ParametresGeneraux.accentColor);
gr.fillArc(0, 0, ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX, ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX, 0, 360);
EncodedImage roundPlaceholder = EncodedImage.createFromImage(tempPlaceholder, true);
final Image reportImage = URLImage.createToStorage(
roundPlaceholder,
photoFilenameInStorage,
currentReport.getPhotoPath(),
ParametresGeneraux.RESIZE_SCALE_WITH_ROUND_MASK
);
And here is the overridden imageAdapter method :
public final static URLImage.ImageAdapter RESIZE_SCALE_WITH_ROUND_MASK = new URLImage.ImageAdapter() {
#Override
public EncodedImage adaptImage(EncodedImage downloadedImage, EncodedImage placeholderImage) {
final Image[] tmp = new Image[1];
if (!Display.getInstance().isEdt()) {
// The image scaling has to be called from EDT
Display.getInstance().callSeriallyAndWait(() -> {
tmp[0] = downloadedImage.scaledLargerRatio(placeholderImage.getWidth(), placeholderImage.getHeight());
if (tmp[0].getWidth() > placeholderImage.getWidth()) {
int diff = tmp[0].getWidth() - placeholderImage.getWidth();
int x = diff / 2;
tmp[0] = tmp[0].subImage(x, 0, placeholderImage.getWidth(), placeholderImage.getHeight(), true);
} else if (tmp[0].getHeight() > placeholderImage.getHeight()) {
int diff = tmp[0].getHeight() - placeholderImage.getHeight();
int y = diff / 2;
tmp[0] = tmp[0].subImage(0, y, Math.min(placeholderImage.getWidth(), tmp[0].getWidth()),
Math.min(placeholderImage.getHeight(), tmp[0].getHeight()), true);
}
});
} else {
tmp[0] = downloadedImage.scaledLargerRatio(placeholderImage.getWidth(), placeholderImage.getHeight());
if (tmp[0].getWidth() > placeholderImage.getWidth()) {
int diff = tmp[0].getWidth() - placeholderImage.getWidth();
int x = diff / 2;
tmp[0] = tmp[0].subImage(x, 0, placeholderImage.getWidth(), placeholderImage.getHeight(), true);
} else if (tmp[0].getHeight() > placeholderImage.getHeight()) {
int diff = tmp[0].getHeight() - placeholderImage.getHeight();
int y = diff / 2;
tmp[0] = tmp[0].subImage(0, y, Math.min(placeholderImage.getWidth(), tmp[0].getWidth()),
Math.min(placeholderImage.getHeight(), tmp[0].getHeight()), true);
}
}
EncodedImage[] image2Return = new EncodedImage[1];
if (!Display.getInstance().isEdt()) {
// The image scaling has to be called from EDT
Display.getInstance().callSeriallyAndWait(() -> {
Image roundMask = Image.createImage(tmp[0].getWidth(), tmp[0].getHeight(), 0xff000000);
Graphics gr = roundMask.getGraphics();
gr.setColor(0xffffff);
gr.fillArc(0, 0, tmp[0].getWidth(), tmp[0].getHeight(), 0, 360);
Object mask = roundMask.createMask();
tmp[0] = tmp[0].applyMask(mask);
image2Return[0] = EncodedImage.createFromImage(tmp[0], false);
});
} else {
Image roundMask = Image.createImage(tmp[0].getWidth(), tmp[0].getHeight(), 0xff000000);
Graphics gr = roundMask.getGraphics();
gr.setColor(0xffffff);
gr.fillArc(0, 0, tmp[0].getWidth(), tmp[0].getHeight(), 0, 360);
Object mask = roundMask.createMask();
tmp[0] = tmp[0].applyMask(mask);
image2Return[0] = EncodedImage.createFromImage(tmp[0], false);
}
return image2Return[0];
}
In the stacktrace, the NPE seems to stem from the overridden URLImage.ImageAdapter :
java.lang.IllegalArgumentException: create image failed for the given
image data of length: 0 at
com.codename1.ui.Image.createImage(Image.java:654) at
com.codename1.ui.EncodedImage.getInternal(EncodedImage.java:365) at
com.codename1.ui.EncodedImage.getInternalImpl(EncodedImage.java:340)
at com.codename1.ui.EncodedImage.getHeight(EncodedImage.java:522) at
com.codename1.ui.Image.scaledLargerRatio(Image.java:899) at
com.my.application.ParametresGeneraux$1.lambda$adaptImage$0(ParametresGeneraux.java:564)
at com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:95) at
com.codename1.ui.Display.processSerialCalls(Display.java:1154) at
com.codename1.ui.Display.edtLoopImpl(Display.java:1098) at
com.codename1.ui.Display.invokeAndBlock(Display.java:1207) at
com.codename1.ui.Display.invokeAndBlock(Display.java:1244) at
com.codename1.ui.URLImage$DownloadCompleted.actionPerformed(URLImage.java:233)
at com.codename1.ui.URLImage$4.onSucess(URLImage.java:301) at
com.codename1.ui.URLImage$4.onSucess(URLImage.java:297) at
com.codename1.util.CallbackDispatcher.run(CallbackDispatcher.java:53)
at com.codename1.ui.Display.processSerialCalls(Display.java:1154) at
com.codename1.ui.Display.edtLoopImpl(Display.java:1098) at
com.codename1.ui.Display.mainEDTLoop(Display.java:999) at
com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120) at
com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)
[EDT] 0:0:0,1 - Codename One revisions:
e5c43877074c18b4b5c7748d000e5cfac75ab749 2318
[EDT] 0:0:0,1 - Exception: java.lang.NullPointerException - null
java.lang.NullPointerException at
com.codename1.impl.javase.JavaSEPort.scale(JavaSEPort.java:3996) at
com.codename1.ui.Image.scale(Image.java:1007) at
com.codename1.ui.Image.scaledImpl(Image.java:953) at
com.codename1.ui.Image.scaled(Image.java:918) at
com.codename1.impl.javase.JavaSEPort$71.save(JavaSEPort.java:7659) at
com.codename1.ui.EncodedImage.scaledEncoded(EncodedImage.java:626) at
com.codename1.ui.EncodedImage.scaled(EncodedImage.java:653) at
com.codename1.ui.Image.scaledLargerRatio(Image.java:904) at
com.my.application.ParametresGeneraux$1.lambda$adaptImage$0(ParametresGeneraux.java:564)
at com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:95) at
com.codename1.ui.Display.processSerialCalls(Display.java:1154) at
com.codename1.ui.Display.edtLoopImpl(Display.java:1098) at
com.codename1.ui.Display.invokeAndBlock(Display.java:1207) at
com.codename1.ui.Display.invokeAndBlock(Display.java:1244) at
com.codename1.ui.URLImage$DownloadCompleted.actionPerformed(URLImage.java:233)
at com.codename1.ui.URLImage$4.onSucess(URLImage.java:301) at
com.codename1.ui.URLImage$4.onSucess(URLImage.java:297) at
com.codename1.util.CallbackDispatcher.run(CallbackDispatcher.java:53)
at com.codename1.ui.Display.processSerialCalls(Display.java:1154) at
com.codename1.ui.Display.edtLoopImpl(Display.java:1098) at
com.codename1.ui.Display.mainEDTLoop(Display.java:999) at
com.codename1.ui.RunnableWrapper.run(RunnableWrapper.java:120) at
com.codename1.impl.CodenameOneThread.run(CodenameOneThread.java:176)
Moreover, a glance in the .cn1 directory shows the URLImage storage file name with the suffix "ImageURLTMP" which does not appear when everything works without NPE.
Finally, if I come back to this form later, everything works as expected (images were shown, no NPE). I tried to test for downloadedImage nullness in imageAdapter but the EncodedImage is not null.
How can I avoid this NPE?
Edit March 1st 2017
Following the answers from #Diamond and #Shai, I believe the NPE occurs because the InfiniteScrollAdapter wants to fill in the screen with rows and consequently launches the download of the same image simultaneously (because it is not in cache). So a solution could be to prevent the InfiniteScrollAdapter to loop (so it becomes finite). How can I do that ?
Please also note that there is not 404 error, the Network monitor shows response code 200 as depicted below. However the image should not be downloaded 3 times, should it ?
Change your ImageAdapter to the following:
public static final URLImage.ImageAdapter RESIZE_SCALE_WITH_ROUND_MASK = new URLImage.ImageAdapter() {
#Override
public EncodedImage adaptImage(EncodedImage downloadedImage, EncodedImage placeholderImage) {
Image tmp = downloadedImage.scaledLargerRatio(placeholderImage.getWidth(), placeholderImage.getHeight());
if (tmp.getWidth() > placeholderImage.getWidth()) {
int diff = tmp.getWidth() - placeholderImage.getWidth();
int x = diff / 2;
tmp = tmp.subImage(x, 0, placeholderImage.getWidth(), placeholderImage.getHeight(), true);
} else if (tmp.getHeight() > placeholderImage.getHeight()) {
int diff = tmp.getHeight() - placeholderImage.getHeight();
int y = diff / 2;
tmp = tmp.subImage(0, y, Math.min(placeholderImage.getWidth(), tmp.getWidth()),
Math.min(placeholderImage.getHeight(), tmp.getHeight()), true);
}
Image roundMask = Image.createImage(tmp.getWidth(), tmp.getHeight(), 0xff000000);
Graphics gr = roundMask.getGraphics();
gr.setColor(0xffffff);
gr.fillArc(0, 0, tmp.getWidth(), tmp.getHeight(), 0, 360);
Object mask = roundMask.createMask();
tmp = tmp.applyMask(mask);
return EncodedImage.createFromImage(tmp, false);
}
#Override
public boolean isAsyncAdapter() {
return true;
}
};
No need to check EDT.
Make sure your tempPlaceholder image is applied to your component first and at the end of your logic, call your URLImage in a callSerially() method:
Image tempPlaceholder = Image.createImage(
ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX,
ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX,
ParametresGeneraux.accentColor);
Graphics gr = tempPlaceholder.getGraphics();
gr.setAntiAliased(true);
gr.setColor(ParametresGeneraux.accentColor);
gr.fillArc(0, 0, ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX, ParametresGeneraux.SIZE_OF_REPORT_PIC_IN_PX, 0, 360);
myComponent.setIcon(tempPlaceholder);
...
//Then call this at the end of everything
Display.getInstance().callSerially(() -> {
EncodedImage roundPlaceholder = EncodedImage.createFromImage(tempPlaceholder, true);
final Image reportImage = URLImage.createToStorage(
roundPlaceholder,
photoFilenameInStorage,
currentReport.getPhotoPath(),
ParametresGeneraux.RESIZE_SCALE_WITH_ROUND_MASK
);
myComponent.setIcon(reportImage);
myComponent.getComponentForm().repaint();
});
Edit:
Based on #Shai's answer, you could check if you are currently downloading the same image and prevent another one from being pulled. Because this usually causes a conflict:
//Declare this at the top of your class
final static private Map<String, Image> LOADED_URLS = new HashMap<>();
//Then change the URLImage image method to this
Display.getInstance().callSerially(() -> {
EncodedImage roundPlaceholder = EncodedImage.createFromImage(tempPlaceholder, true);
final Image reportImage = LOADED_URLS.containsKey(photoFilenameInStorage) ? LOADED_URLS.get(photoFilenameInStorage)
: URLImage.createToStorage(
roundPlaceholder,
photoFilenameInStorage,
currentReport.getPhotoPath(),
ParametresGeneraux.RESIZE_SCALE_WITH_ROUND_MASK
);
LOADED_URLS.put(photoFilenameInStorage, reportImage);
myComponent.setIcon(reportImage);
myComponent.getComponentForm().repaint();
});
In your adapter check if downloadedImage.getData() is null. I assume it's not and it's a 404 error page or something similar to that.
In that case your adapter can catch the exception and just return a fallback that matches what you expect to see when no image exists.
This works the second time around since the system sees the tmp file and assumes a download is in progress so it doesn't invoke the download code again. The tmp file is later renamed to the final downloadable file.

How many pixels is a single character in libgdx [duplicate]

I have been trying to figure out a way to center text on a button, but can't find an easy, multi-purpose way to. I can do it, but it will only work for a certain string, not for any string. i would like to know if there is a way to center any string on a button. My button in this case is 185x50.
I have been able to center this button on the screen, like so:
buttonX = WIDTH / 2 - (screen.getRegionWidth() / 2);
buttonY = HEIGHT / 2 - (screen.getRegionHeight() / 2);
Any help would be much appreciated. :)
Updated the answer to libgdx version 1.7.1-SNAPSHOT:
The easiest way to do this, is to use the TextButton class from libgdx. The text from a TextButton is centered by default. This still works!
Updated example:
final BitmapFont font = new BitmapFont();
final String text = "Test";
final GlyphLayout layout = new GlyphLayout(font, text);
// or for non final texts: layout.setText(font, text);
final float fontX = objectX + (objectWidth - layout.width) / 2;
final float fontY = objectY + (objectHeight + layout.height) / 2;
font.draw(batch, layout, fontX, fontY);
Outdated example:
This no longer works!
If you do not want to use it, you can get the font width and height with:
font.getBounds("Test text");
So you can do something like this:
String fontText = "";
fontX = buttonX + buttonWidth/2 - font.getBounds(fontText).width/2;
fontY = buttonY + buttonHeight/2 + font.getBounds(fontText).height/2;
For the newer version of libgdx the function BitMapFont.getBounds() isn't there in api anymore. You can use GlyphLayout to get bounds.For example,
BitmapFont font;
SpriteBatch spriteBatch;
//... Load any font of your choice first
FreeTypeFontGenerator fontGenerator = new FreeTypeFontGenerator(
Gdx.files.internal("myFont.ttf")
);
FreeTypeFontGenerator.FreeTypeFontParameter freeTypeFontParameter =
new FreeTypeFontGenerator.FreeTypeFontParameter();
freeTypeFontParameter.size = size;
fontGenerator.generateData(freeTypeFontParameter);
font = fontGenerator.generateFont(freeTypeFontParameter);
//Initialize the spriteBatch as requirement
GlyphLayout glyphLayout = new GlyphLayout();
String item = "Example";
glyphLayout.setText(font,item);
float w = glyphLayout.width;
font.draw(spriteBatch, glyphLayout, (Game.SCREEN_WIDTH - w)/2, y);
Try the following:
label.setPosition(Gdx.graphics.getWidth()/2-(label.getPrefWidth()/2),Gdx.graphics.getHeight()-(label.getPrefHeight()/2));

Likelihood Ratio Java

I'm searching for a library or an example on how to implement in java a likelihood ratio test like in matlab.
I have two different vector of double values and want to receive a scalar value.
Every value correspond to a feature for my machine learning algorithm so one the first vector is the training pattern and the second one a test.
Could you please help me?
On matlab i just use division on two matrix like LR= test_matrix/training_matrix
I've tryied with apache mahout but i'm not sure i'm using it correctly.
Here the code:
FastByIDMap<FastByIDMap<Long>> timestamps = new FastByIDMap<>();
Collection<Preference> prefs = new ArrayList<>(2);
FastByIDMap<Collection<Preference>> data = new FastByIDMap<>(); //Preferecens for user0
Preference newPrefs = new GenericPreference(0, 0, (float) -0.5);
Preference pref = new GenericPreference(0, 1, 50);
Preference pref2 = new GenericPreference(0, 2, 51);
prefs.add(newPrefs);
prefs.add(pref);
prefs.add(pref2);
data.put(0, prefs);
Collection<Preference> prefs_1 = new ArrayList<>(2);
newPrefs = new GenericPreference(1, 0, (float) -0.5);
pref = new GenericPreference(1, 1, 50);
pref2 = new GenericPreference(1, 2, 51);
prefs_1.add(newPrefs);
prefs_1.add(pref);
prefs_1.add(pref2);
data.put(1, prefs_1);
GenericDataModel model = new GenericDataModel(GenericDataModel.toDataMap(data, true), timestamps);
FastByIDMap<PreferenceArray> us = model.getRawUserData();
System.out.println("us:"+ us.toString());
LogLikelihoodSimilarity l = new LogLikelihoodSimilarity(model);
System.out.println(l.userSimilarity(0, 1));
In this case, user similarity alwasy return 0.

Multiple tile layers on osmdroid

Currently I am loading one tile data-layer over an OSMdroid basemap with
final MapTileProviderBasic tileProvider =
new MapTileProviderBasic(getApplicationContext());
final ITileSource tileSource =
new XYTileSource("MyCustomTiles", null, 1, 16, 256, ".png",
"http://a.url.to/custom-tiles/");
tileProvider.setTileSource(tileSource);
final TilesOverlay tilesOverlay =
new TilesOverlay(tileProvider, this.getBaseContext());
tilesOverlay.setLoadingBackgroundColor(Color.TRANSPARENT);
osmv.getOverlays().add(tilesOverlay);
Is it possible to render multiple data layers on top of each other over the BaseMap or can I only display one data layer at a time?
I found this example for GoogleMaps, but haven't found some example OSMdroid code dealing with multipe tileSources at a time.
Yes, of course you can. You just have to add another TilesOverlay to the map. The overlays(also tilesOverlays) get drawn consecutively, starting at the list's lowest index(=0).
Here's an example:
//create the first tilesOverlay
final MapTileProviderBasic tileProvider = new MapTileProviderBasic(getApplicationContext());
final ITileSource tileSource = new XYTileSource("MyCustomTiles", null, 1, 16, 256, ".png",
"http://a.url.to/custom-tiles/");
tileProvider.setTileSource(tileSource);
final TilesOverlay tilesOverlay = new TilesOverlay(tileProvider, this.getBaseContext());
tilesOverlay.setLoadingBackgroundColor(Color.TRANSPARENT);
//create the second one
final MapTileProviderBasic anotherTileProvider = new MapTileProviderBasic(getApplicationContext());
final ITileSource anotherTileSource = new XYTileSource("MyCustomTiles", null, 1, 16, 256, ".png",
"http://a.secondurl.to/custom-tiles/");
anotherTileProvider.setTileSource(anotherTileSource);
final TilesOverlay secondTilesOverlay = new TilesOverlay(anotherTileProvider, this.getBaseContext());
secondTilesOverlay.setLoadingBackgroundColor(Color.TRANSPARENT);
// add the first tilesOverlay to the list
osmv.getOverlays().add(tilesOverlay);
// add the second tilesOverlay to the list
osmv.getOverlays().add(secondTilesOverlay);

Categories

Resources