I have a long standing problem with images (used for map pins) I am using and it keeps getting worse as resolutions get higher. If I use one image, it is fine to just have it in drawable directories and specify that image. Works find with different sizes and resolutions. However, I am pulling the image name from a database on the fly. So it is working fine to have the images in the assets directory but then it is one and only one image for all resolutions. Not good nowadays as they are too small on higher end phones now.
So my goal is to grab the image name from the database and then be able to use the drawable directories and have different sizes. It seems like this would be possible but everything I try fails.
This works specifying one image from the resources directories:
public void run(){
if (!(llat == 0) && !(llon == 0)) {
if (ests == null || ests.size() == 0
|| poisPinpoints.size() == 0) {
ests = DBManager.getEstablishments();
for (Establishment est : ests) {
try {
est_pin_bmp = BitmapFactory.decodeResource(getResources(),R.drawable.mil_pushpin);
poisPinpoints.put(
est.getPoiType().getPushpin(), est_pin_bmp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
This code is used when I have multiple images pulled from the database...but it is only one size from the assets directory:
public void run(){
if (!(llat == 0) && !(llon == 0)) {
if (ests == null || ests.size() == 0
|| poisPinpoints.size() == 0) {
ests = DBManager.getEstablishments();
for (Establishment est : ests) {
try {
Bitmap bm = BitmapFactory
.decodeStream(PlayPlaces.this
.getAssets().open(
est.getPoiType()
.getPushpin()));
poisPinpoints.put(
est.getPoiType().getPushpin(), bm);
} catch (Exception e) {
e.printStackTrace();
}
}
}
you probably want to take a look into this method Resources.getIdentifier()
with it you can specify something like:
String resName = est.getPoiType().getPushpin();
int drawId = getResources().getIdentifier(resName , "drawable", getPackageName());
est_pin_bmp = BitmapFactory.decodeResource(getResources(), drawId);
Related
I trying to create a custom photo gallery which the user can store Images from MediaStore photo gallery,
And my target is that the user can only the store different Image in database, if it is a duplicate Image it will not store .So , Im thinking hey, I can use the filepath as sort of A Id to check for duplicate Images. But evertime I restart the app and repick the same picture the Uri/filepath is not the same espicially the lastpart of the filePath/Uri
My Weird Implementation to Check duplicate:
public void checkAndSetPhotoGalleryData() throws IOException {
RoomDB db = RoomDB.getInstance(this);
PhotoGalleryData photoGalleryData = new PhotoGalleryData();
String stringUri = String.valueOf(imageUri);
String lastPartFile = stringUri.substring(stringUri.lastIndexOf('/')+1);
TextView testThis = findViewById(R.id.testName);
testThis.setText(db_path);
if(photoGarList.isEmpty()) {
try {
InputStream iStream = getContentResolver().openInputStream(imageUri);
byte[] inputData = getBytes(iStream);
photoGalleryData.setKey_Value_Quiz(String.valueOf(lastPartFile));
photoGalleryData.setPhoto(inputData);
db.questionDao().insert(photoGalleryData);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}if(!photoGarList.isEmpty())
{for(int i = 0; i<photoGarList.size();i++){
if (photoGarList.get(i).getKey_Value_Quiz().length() > 0 && !photoGarList.isEmpty() && photoGarList.get(i).getKey_Value_Quiz().equals(String.valueOf(lastPartFile))) {
showLongToast("Are Identical");
}
if (photoGarList.get(i).getKey_Value_Quiz().length() > 0 && !photoGarList.isEmpty() && !photoGarList.get(i).getKey_Value_Quiz().equals(String.valueOf(lastPartFile)) && i == photoGarList.size()-1) {
try {
InputStream iStream = getContentResolver().openInputStream(imageUri);
byte[] inputData = getBytes(iStream);
photoGalleryData.setKey_Value_Quiz(String.valueOf(lastPartFile));
photoGalleryData.setPhoto(inputData);
db.questionDao().insert(photoGalleryData);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
lastPart of filePath:
///both of this are the same picture:
KeyValue:924270434
KeyValue:239256090
I guess that for security reason they change the last part every time, So I want to know is there any constant factor of a picture except for byte[] or Bitmap(Size is to Huge to store at once and this is not the case).
You could use simple pixel by pixel comparison of the images.
Try to use ImageMagic:
ImageMagic
Or you could try Java OpenCV: How to compare two images using Java OpenCV library
I'm trying out detecting multiple augmented images with AR core, with
https://developers.google.com/ar/develop/java/augmented-images/guide
and other online tutorials. Currently, I have the database setup and loaded with images. However
Collection<AugmentedImage> augmentedImages = frame.getUpdatedTrackables(AugmentedImage.class);
did not seem to capture and match the feature points of my images in my db.
Can you advise me about what I need to do?
I have set up and loaded multiple images from db. The app is able to detect only 1 image previously. However, after tweaking my code to detect multiple images, it did not work properly.
Tried researching and debugging however, still unable to solve it.
private void onUpdateFrame(FrameTime frameTime)
{
Frame frame = arFragment.getArSceneView().getArFrame();
Collection<AugmentedImage> augmentedImages = frame.getUpdatedTrackables(AugmentedImage.class);
for (AugmentedImage augmentedImage : augmentedImages)
{
int i =augmentedImages.size();
Log.d("NoImage",""+i);
if (augmentedImage.getTrackingState() == TrackingState.TRACKING)
{
if (augmentedImage.getName().contains("img1") && !modelAdded)
{
renderObject(arFragment, augmentedImage.createAnchor(augmentedImage.getCenterPose()),R.raw.car);
modelAdded = true;
}
else if (augmentedImage.getName().contains("img2") && !modelAdded)
{
renderObject(arFragment, augmentedImage.createAnchor(augmentedImage.getCenterPose()), R.raw.car);
modelAdded = true;
}
else if (augmentedImage.getName().contains("img3") && !modelAdded)
{
renderObject(arFragment, augmentedImage.createAnchor(augmentedImage.getCenterPose()), R.raw.car);
modelAdded = true;
}
}
}
}
i have this code below, but it is not efficient at all, it is very very slow and more pictures i have to compare more long time it takes.
For example i have 500 pictures, each process lasts 2 minutes, 500 x 2 min =1000 min !
the specificity is as soon as there is picture same as compared, move it to another folder. then retrieve the rest files to compare i++
any idea ?
public static void main(String[] args) throws IOException {
String PicturesFolderPath=null;
String removedFolderPath=null;
String pictureExtension=null;
if(args.length>0) {
PicturesFolderPath=args[0];
removedFolderPath=args[1];
pictureExtension=args[2];
}
if(StringUtils.isBlank(pictureExtension)) {
pictureExtension="jpg";
}
if(StringUtils.isBlank(removedFolderPath)) {
removedFolderPath=Paths.get(".").toAbsolutePath().normalize().toString()+"/removed";
}
if(StringUtils.isBlank(PicturesFolderPath)) {
PicturesFolderPath=Paths.get(".").toAbsolutePath().normalize().toString();
}
System.out.println("path to find pictures folder "+PicturesFolderPath);
System.out.println("path to find removed pictures folder "+removedFolderPath);
Collection<File> fileList = FileUtils.listFiles(new File(PicturesFolderPath), new String[] { pictureExtension }, false);
System.out.println("there is "+fileList.size()+" files founded with extention "+pictureExtension);
Iterator<File> fileIterator=fileList.iterator();
//Iterator<File> loopFileIterator=fileList.iterator();
File dest=new File(removedFolderPath);
while(fileIterator.hasNext()) {
File file=fileIterator.next();
System.out.println("process image :"+file.getName());
//each new iteration we retrieve the files staying
Collection<File> list = FileUtils.listFiles(new File(PicturesFolderPath), new String[] { pictureExtension }, false);
for(File f:list) {
if(compareImage(file,f) && !file.getName().equals(f.getName()) ) {
String filename=file.getName();
System.out.println("file :"+file.getName() +" equal to "+f.getName()+" and will be moved on removed folder");
File existFile=new File(removedFolderPath+"/"+file.getName());
if(existFile.exists()) {
existFile.delete();
}
FileUtils.moveFileToDirectory(file, dest, false);
fileIterator.remove();
System.out.println("file :"+filename+" removed");
break;
}
}
}
}
// This API will compare two image file //
// return true if both image files are equal else return false//**
public static boolean compareImage(File fileA, File fileB) {
try {
// take buffer data from botm image files //
BufferedImage biA = ImageIO.read(fileA);
DataBuffer dbA = biA.getData().getDataBuffer();
int sizeA = dbA.getSize();
BufferedImage biB = ImageIO.read(fileB);
DataBuffer dbB = biB.getData().getDataBuffer();
int sizeB = dbB.getSize();
// compare data-buffer objects //
if(sizeA == sizeB) {
for(int i=0; i<sizeA; i++) {
if(dbA.getElem(i) != dbB.getElem(i)) {
return false;
}
}
return true;
}
else {
return false;
}
}
catch (Exception e) {
e.printStackTrace();
return false;
}
}
The already mentioned answer should help you a bit, as considering the width and height of a picture should exclude more candidate pairs quickly.
However, you still have a big problem: For every new file, you read all old files. The number of comparisons grows quadratically and with doing ImageIO.read for every step, it simply must be slow.
You need some fingerprints, which can be compared very fast. You can't use fingerprinting over the whole file content as its infested by the metadata, but you can fingerprint the image data alone.
Just iterate over the image data of a file (like you do), and compute e.g., MD5 hash of it. Store it e.g., as a String in HashSet and you'll get a very fast lookup.
Some untested code
For every image file you want to compare, you compute (using Guava's hashing)
HashCode imageFingerprint(File file) {
Hasher hasher = Hashing.md5().newHasher();
BufferedImage image = ImageIO.read(file);
DataBuffer buffer = image.getData().getDataBuffer();
int size = buffer.getSize();
for(int i=0; i<size; i++) {
hasher.putInt(buffer.getElem(i));
}
return hasher.hash();
}
The computation works with the image data only, just like compareImage in the question, so the metadata get ignored.
Instead of searching for a duplicate in a directory, you compute the fingerprints of all its files and store them in a HashSet<HashCode>. For a new file, you compute its fingerprint and look it up in the set.
I'd like to make my Java program compare the actual screen with a picture (screenshot).
I don't know if it's possible, but I have seen it in Jitbit (a macro recorder) and I would like to implement it myself. (Maybe with that example you understand what I mean).
Thanks
----edit-----
In other words, is it possible to check if an image is showing in? To find and compare that pixels in the screen?
You may try aShot: documentation link
1) aShot can ignore areas you mark with special color.
2) aShot can provide image which display difference between images.
private void compareTowImages(BufferedImage expectedImage, BufferedImage actualImage) {
ImageDiffer imageDiffer = new ImageDiffer();
ImageDiff diff = imageDiffer
.withDiffMarkupPolicy(new PointsMarkupPolicy()
.withDiffColor(Color.YELLOW))
.withIgnoredColor(Color.MAGENTA)
.makeDiff(expectedImage, actualImage);
// areImagesDifferent will be true if images are different, false - images the same
boolean areImagesDifferent = diff.hasDiff();
if (areImagesDifferent) {
// code in case of failure
} else {
// Code in case of success
}
}
To save image with differences:
private void saveImage(BufferedImage image, String imageName) {
// Path where you are going to save image
String outputFilePath = String.format("target/%s.png", imageName);
File outputFile = new File(outputFilePath);
try {
ImageIO.write(image, "png", outputFile);
} catch (IOException e) {
// Some code in case of failure
}
}
You can do this in two steps:
Create a screenshot using awt.Robot
BufferedImage image = new Robot().createScreenCapture(new Rctangle(Toolkit.getDefaultToolkit().getScreenSize()));
ImageIO.write(image, "png", new File("/screenshot.png"));
Compare the screenshots using something like that: How to check if two images are similar or not using openCV in java?
Have a look at Sikuli project. Their automation engine is based on image comparison.
I guess, internally they are still using OpenCV for calculating image similarity, but there are plenty of OpenCV Java bindings like this, which allow to do so from Java.
Project source code is located here: https://github.com/sikuli/sikuli
Ok then, so I found an answer after a few days.
This method takes the screenshot:
public static void takeScreenshot() {
try {
BufferedImage image = new Robot().createScreenCapture(new Rectangle(490,490,30,30));
/* this two first parameters are the initial X and Y coordinates. And the last ones are the increment of each axis*/
ImageIO.write(image, "png", new File("C:\\Example\\Folder\\capture.png"));
} catch (IOException e) {
e.printStackTrace();
} catch (HeadlessException e) {
e.printStackTrace();
} catch (AWTException e) {
e.printStackTrace();
}
}
And this other one will compare the images
public static String compareImage() throws Exception {
// savedImage is the image we want to look for in the new screenshot.
// Both must have the same width and height
String c1 = "savedImage";
String c2 = "capture";
BufferedInputStream in = new BufferedInputStream(new FileInputStream(c1
+ ".png"));
BufferedInputStream in1 = new BufferedInputStream(new FileInputStream(
c2 + ".png"));
int i, j;
int k = 1;
while (((i = in.read()) != -1) && ((j = in1.read()) != -1)) {
if (i != j) {
k = 0;
break;
}
}
in.close();
in1.close();
if (k == 1) {
System.out.println("Ok...");
return "Ok";
} else {
System.out.println("Fail ...");
return "Fail";
}
}
I'm using Google Drive SDK v2 on Android to get the list of root folders. Currently I see these required steps - which seem to load forever. Is there no faster way?
I tried to use the search with the q= parameter but I don't get it to work (FileList vs. Files.List) - different API levels?
FileList files = drive.files().list().setQ("'root' in parents and mimeType='application/vnd.google-apps.folder' and trashed=false");
This is what I do currently:
About about = drive.about().get().execute();
if (about != null) {
ChildList childList = drive.children().list(about.getRootFolderId()).execute();
if (childList != null) {
List<ChildReference> listChildReference = childList.getItems();
for (ChildReference childReference : listChildReference) {
File file = drive.files().get(childReference.getId()).execute();
if (file != null) {
String fileExtension = file.getFileExtension();
String mimeType = file.getMimeType();
if (mimeType != null
&& mimeType.equals("application/vnd.google-apps.folder")
&& (fileExtension == null || fileExtension.equals(""))) {
Log.d(this.getClass().getName(), file.getTitle());
}
}
}
}
}
What's the fastest for an Android app?
Thanks in advance.
My personal opinion is avoid the Drive SDK and call the REST API directly. It's a fairly simple API, and the way the documentation is structured, you are forced to understand it anyway in order to use the SDK. You have the benefit that if something doesn't work, you can directly compare your app with what's happening on the wire and resolve any problems.
Found it:
#Override
protected ArrayList<File> doInBackground(final Void... voids) {
ArrayList<File> result = new ArrayList<File>();
Files.List request = null;
boolean ok = true;
do {
try {
request = drive
.files()
.list()
.setMaxResults(200)
.setQ("'root' in parents and mimeType='application/vnd.google-apps.folder' and trashed=false");
FileList files = request.execute();
result.addAll(files.getItems());
request.setPageToken(files.getNextPageToken());
} catch (IOException exception) {
ok = false;
}
} while (ok && request.getPageToken() != null && request.getPageToken().length() > 0);
return result;
}