Add Image Recognition Lab

This commit is contained in:
2025-11-11 19:19:46 +01:00
parent 41bc409a0d
commit 1d1503c877
13 changed files with 502 additions and 2 deletions

4
.gitignore vendored
View File

@@ -4,4 +4,6 @@ build
*.txt *.txt
node_modules node_modules
.env .env
output

View File

@@ -0,0 +1,33 @@
import org.springframework.boot.gradle.plugin.SpringBootPlugin
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
description = "Sentiment Analysis Lab"
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
repositories {
mavenCentral()
}
dependencyManagement {
imports {
mavenBom SpringBootPlugin.BOM_COORDINATES
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'ai.djl:api:0.33.0'
implementation 'ai.djl.pytorch:pytorch-engine:0.33.0'
implementation 'ai.djl.pytorch:pytorch-model-zoo:0.33.0'
runtimeOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 632 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 KiB

View File

@@ -0,0 +1 @@
Some images that you can use for prediction are added here

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

View File

@@ -0,0 +1,376 @@
package com.example.img;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.List;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Product Image Recognition Lab
* A simplified lab for beginners to understand image processing concepts
* without complex dependencies.
*/
@SpringBootApplication
public class ProductRecognitionNewModel {
// Constants for image analysis
// private static final int SAMPLE_SIZE = 10;
private static final int RESIZE_WIDTH = 100;
private static final int RESIZE_HEIGHT = 100;
public static void main(String[] args) {
try {
System.out.println("Starting Product Recognition Lab");
// Step 1: Create necessary directories
File projectDir = new File("ImageRecognitionLab");
File imagesDir = new File(projectDir, "images");
File outputDir = new File(projectDir, "output");
if (!Files.exists(outputDir.toPath())) {
Files.createDirectories(outputDir.toPath());
}
// Step 2: Process each image in the folder
File[] imageFiles = imagesDir.listFiles();
if (imageFiles != null && imageFiles.length > 0) {
for (File imageFile : imageFiles) {
if (imageFile.isFile() && (imageFile.getName().endsWith(".jpg") ||
imageFile.getName().endsWith(".jpeg") ||
imageFile.getName().endsWith(".png"))) {
processImage(imageFile, outputDir.toPath());
}
}
} else {
System.out.printf("No images found in directory: %s%n", imagesDir);
System.out.println("Please add some product images to the 'images' folder.");
}
System.out.println("Product recognition completed successfully!");
} catch (Exception e) {
System.err.println("Error occurred: " + e.getMessage());
e.printStackTrace();
}
}
/**
* Process a single image file
*/
private static void processImage(File imageFile, Path outputDir) throws IOException {
System.out.println("Analyzing image: " + imageFile.getName());
// Step 1: Load the image
BufferedImage originalImage = ImageIO.read(imageFile);
if (originalImage == null) {
System.err.println("Failed to load image: " + imageFile.getName());
return;
}
// Step 2: Extract image features
Map<String, Double> features = extractImageFeatures(originalImage);
// Step 3: Classify the image based on features
List<Prediction> predictions = classifyImage(features, imageFile.getName());
// Step 4: Print the results
System.out.println("Top 5 predictions for " + imageFile.getName() + ":");
for (Prediction p : predictions) {
System.out.printf("%-30s: %.2f%%\n", p.getLabel(), p.getProbability() * 100);
}
System.out.println("-----------------------------------------\n");
// Step 5: Save the results to a file
saveResultsToFile(imageFile.getName(), predictions, outputDir);
// Optional: Save a processed version of the image
saveProcessedImage(originalImage, imageFile.getName(), outputDir);
}
/**
* Extract basic features from the image
*/
private static Map<String, Double> extractImageFeatures(BufferedImage image) {
Map<String, Double> features = new HashMap<>();
// Resize image for consistent analysis
BufferedImage resized = resizeImage(image, RESIZE_WIDTH, RESIZE_HEIGHT);
// Calculate average color components
double avgRed = 0;
double avgGreen = 0;
double avgBlue = 0;
// Calculate brightness histogram
int[] brightnessHistogram = new int[256];
// Sample pixels from the image
for (int y = 0; y < resized.getHeight(); y++) {
for (int x = 0; x < resized.getWidth(); x++) {
Color color = new Color(resized.getRGB(x, y));
avgRed += color.getRed();
avgGreen += color.getGreen();
avgBlue += color.getBlue();
// Calculate brightness (simple average of RGB)
int brightness = (color.getRed() + color.getGreen() + color.getBlue()) / 3;
brightnessHistogram[brightness]++;
}
}
int totalPixels = resized.getWidth() * resized.getHeight();
avgRed /= totalPixels;
avgGreen /= totalPixels;
avgBlue /= totalPixels;
features.put("avgRed", avgRed / 255.0);
features.put("avgGreen", avgGreen / 255.0);
features.put("avgBlue", avgBlue / 255.0);
// Calculate color ratios
double redGreenRatio = avgRed / (avgGreen + 1);
double blueGreenRatio = avgBlue / (avgGreen + 1);
double redBlueRatio = avgRed / (avgBlue + 1);
features.put("redGreenRatio", redGreenRatio);
features.put("blueGreenRatio", blueGreenRatio);
features.put("redBlueRatio", redBlueRatio);
// Calculate brightness stats
double avgBrightness = (avgRed + avgGreen + avgBlue) / 3 / 255.0;
features.put("avgBrightness", avgBrightness);
// Analyze edge density (simplified)
double edgeDensity = calculateEdgeDensity(resized);
features.put("edgeDensity", edgeDensity);
// Calculate texture uniformity (simplified)
double textureUniformity = calculateTextureUniformity(brightnessHistogram, totalPixels);
features.put("textureUniformity", textureUniformity);
return features;
}
/**
* Resize an image to specified dimensions
*/
private static BufferedImage resizeImage(BufferedImage original, int width, int height) {
BufferedImage resized = new BufferedImage(width, height, original.getType());
Graphics2D g = resized.createGraphics();
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.drawImage(original, 0, 0, width, height, null);
g.dispose();
return resized;
}
/**
* Calculate a simple edge density metric
*/
private static double calculateEdgeDensity(BufferedImage image) {
int edgeCount = 0;
int totalPixels = (image.getWidth() - 1) * (image.getHeight() - 1);
for (int y = 0; y < image.getHeight() - 1; y++) {
for (int x = 0; x < image.getWidth() - 1; x++) {
Color pixel = new Color(image.getRGB(x, y));
Color pixelRight = new Color(image.getRGB(x + 1, y));
Color pixelBelow = new Color(image.getRGB(x, y + 1));
int diffX = Math.abs(pixel.getRed() - pixelRight.getRed()) +
Math.abs(pixel.getGreen() - pixelRight.getGreen()) +
Math.abs(pixel.getBlue() - pixelRight.getBlue());
int diffY = Math.abs(pixel.getRed() - pixelBelow.getRed()) +
Math.abs(pixel.getGreen() - pixelBelow.getGreen()) +
Math.abs(pixel.getBlue() - pixelBelow.getBlue());
// If the difference is significant, count as an edge
if (diffX > 100 || diffY > 100) {
edgeCount++;
}
}
}
return (double) edgeCount / totalPixels;
}
/**
* Calculate texture uniformity based on brightness histogram
*/
private static double calculateTextureUniformity(int[] histogram, int totalPixels) {
double uniformity = 0;
for (int i = 0; i < histogram.length; i++) {
double p = (double) histogram[i] / totalPixels;
uniformity += p * p;
}
return uniformity;
}
/**
* Classify the image based on extracted features
*/
private static List<Prediction> classifyImage(Map<String, Double> features, String filename) {
List<Prediction> predictions = new ArrayList<>();
// Using filename for simulation, since this is just a demonstration
filename = filename.toLowerCase();
// Initialize with low probabilities
predictions.add(new Prediction("laptop", 0.01));
predictions.add(new Prediction("water bottle", 0.01));
predictions.add(new Prediction("coffee mug", 0.01));
predictions.add(new Prediction("book", 0.01));
predictions.add(new Prediction("smartphone", 0.01));
// Feature-based classification (simplified rules)
double avgRed = features.get("avgRed");
double avgGreen = features.get("avgGreen");
double avgBlue = features.get("avgBlue");
double edgeDensity = features.get("edgeDensity");
double textureUniformity = features.get("textureUniformity");
// Example classification rules (simplified)
// These are just for demonstration purposes, not accurate classification
// Dark colors with high edge density might be electronic devices
if (avgRed < 0.5 && avgGreen < 0.5 && avgBlue < 0.5 && edgeDensity > 0.1) {
predictions.get(0).setProbability(0.6); // laptop
predictions.get(4).setProbability(0.3); // smartphone
}
// Blue tones might suggest water bottles
if (avgBlue > avgRed && avgBlue > avgGreen) {
predictions.get(1).setProbability(0.7); // water bottle
}
// High uniformity might suggest solid objects like mugs
if (textureUniformity > 0.1 && avgRed > 0.3) {
predictions.get(2).setProbability(0.65); // coffee mug
}
// Medium brightness with texture might be books
if (avgRed > 0.3 && avgRed < 0.7 && textureUniformity < 0.1) {
predictions.get(3).setProbability(0.55); // book
}
// Override with filename-based simulated results for this demo
if (filename.contains("laptop")) {
predictions.get(0).setProbability(0.92); // laptop
predictions.get(4).setProbability(0.05); // smartphone
} else if (filename.contains("bottle") || filename.contains("water")) {
predictions.get(1).setProbability(0.89); // water bottle
} else if (filename.contains("mug") || filename.contains("coffee")) {
predictions.get(2).setProbability(0.94); // coffee mug
} else if (filename.contains("book")) {
predictions.get(3).setProbability(0.91); // book
} else if (filename.contains("phone") || filename.contains("smartphone")) {
predictions.get(4).setProbability(0.95); // smartphone
predictions.get(0).setProbability(0.03); // laptop
}
// Sort by probability
predictions.sort((a, b) -> Double.compare(b.getProbability(), a.getProbability()));
return predictions;
}
/**
* Save the recognition results to a text file
*/
private static void saveResultsToFile(String imageName, List<Prediction> results, Path outputDir)
throws IOException {
// Create a file named after the image
String filename = imageName.substring(0, imageName.lastIndexOf('.')) + "_results.txt";
Path outputFile = outputDir.resolve(filename);
// Write the results to the file
try (FileWriter writer = new FileWriter(outputFile.toFile())) {
writer.write("Recognition results for: " + imageName + "\n");
writer.write("-----------------------------------------\n");
for (Prediction p : results) {
writer.write(String.format("%-30s: %.2f%%\n",
p.getLabel(),
p.getProbability() * 100));
}
writer.write("\n\nImage Analysis:\n");
writer.write("This is a simplified image analysis demo that shows how\n");
writer.write("basic image processing can extract features like color,\n");
writer.write("texture, and edges. In a real AI system, these features\n");
writer.write("would be inputs to a machine learning model trained on\n");
writer.write("thousands of product images.\n");
}
System.out.println("Results saved to file: " + outputFile);
}
/**
* Save a processed version of the image
*/
private static void saveProcessedImage(BufferedImage original, String imageName, Path outputDir) {
try {
// Create a copy of the image to draw on
BufferedImage processed = new BufferedImage(
original.getWidth(),
original.getHeight(),
BufferedImage.TYPE_INT_RGB
);
Graphics2D g = processed.createGraphics();
g.drawImage(original, 0, 0, null);
// Add a simple border to show processing
g.setColor(Color.GREEN);
g.setStroke(new BasicStroke(5));
g.drawRect(0, 0, processed.getWidth() - 1, processed.getHeight() - 1);
// Add text showing it's been analyzed
g.setColor(Color.WHITE);
g.setFont(new Font("Arial", Font.BOLD, 20));
g.drawString("Analyzed", 20, 40);
g.dispose();
// Save the processed image
String outputFilename = imageName.substring(0, imageName.lastIndexOf('.')) + "_processed.jpg";
Path outputFile = outputDir.resolve(outputFilename);
ImageIO.write(processed, "jpg", outputFile.toFile());
} catch (IOException e) {
System.err.println("Error saving processed image: " + e.getMessage());
}
}
/**
* A simple class to hold a prediction label and its probability
*/
private static class Prediction {
private final String label;
private double probability;
public Prediction(String label, double probability) {
this.label = label;
this.probability = probability;
}
public String getLabel() {
return label;
}
public double getProbability() {
return probability;
}
public void setProbability(double probability) {
this.probability = probability;
}
}
}

View File

@@ -0,0 +1,73 @@
package com.example.img;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import ai.djl.ModelException;
import ai.djl.inference.Predictor;
import ai.djl.modality.Classifications;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
import ai.djl.modality.cv.transform.Resize;
import ai.djl.modality.cv.transform.ToTensor;
import ai.djl.modality.cv.translator.ImageClassificationTranslator;
import ai.djl.repository.zoo.Criteria;
import ai.djl.repository.zoo.ZooModel;
import ai.djl.translate.TranslateException;
import ai.djl.translate.Translator;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import org.springframework.core.io.Resource;
import java.io.InputStream;
@SpringBootApplication
public class ProductRecognitionPreTrainedModel {
public static void main(String[] args) throws IOException, ModelException, TranslateException {
// Path to your image file
String imagePath = "ImageRecognitionLab/images/pill_bottle.png";
// Load from classpath:
// PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
// Resource resource = resolver.getResource("classpath:pill_bottle.png");
// InputStream is = resource.getInputStream();
try (InputStream is = new FileInputStream(imagePath)) {
// Load image
Image img = ImageFactory.getInstance().fromInputStream(is);
// Run prediction
Classifications predictions = predict(img);
// Print results
System.out.println("Top 5 Predictions:");
predictions.topK(5).forEach(System.out::println);
}
}
public static Classifications predict(Image image) throws IOException, ModelException, TranslateException {
// Define translator (preprocessing)
Translator<Image, Classifications> translator = ImageClassificationTranslator.builder()
.addTransform(new Resize(224, 224))
.addTransform(new ToTensor())
.optApplySoftmax(true)
.build();
// Updated criteria to use explicit model from TorchHub
Criteria<Image, Classifications> criteria = Criteria.builder()
.setTypes(Image.class, Classifications.class)
.optTranslator(translator)
.optArtifactId("resnet") // Use explicit model name
.optEngine("PyTorch") // Specify engine
.build();
try (ZooModel<Image, Classifications> model = criteria.loadModel();
Predictor<Image, Classifications> predictor = model.newPredictor()) {
return predictor.predict(image);
}
}
}

View File

@@ -0,0 +1 @@
spring.application.name=img

View File

@@ -0,0 +1,13 @@
package com.example.img;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ImgApplicationTests {
@Test
void contextLoads() {
}
}

View File

@@ -8,4 +8,5 @@ include 'InventoryManagementSystem'
include 'SmartClinicManagementSystem:app' include 'SmartClinicManagementSystem:app'
include 'SoftwareDevChatbot' include 'SoftwareDevChatbot'
include 'RegressionPredictionLab' include 'RegressionPredictionLab'
include 'SentimentAnalysisLab' include 'SentimentAnalysisLab'
include 'ImageRecognitionLab'