diff --git a/.gitignore b/.gitignore index f8506bd..ea3a892 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,6 @@ build *.txt node_modules -.env \ No newline at end of file +.env + +output \ No newline at end of file diff --git a/ImageRecognitionLab/build.gradle b/ImageRecognitionLab/build.gradle new file mode 100644 index 0000000..9df4e78 --- /dev/null +++ b/ImageRecognitionLab/build.gradle @@ -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' +} \ No newline at end of file diff --git a/ImageRecognitionLab/images/book.png b/ImageRecognitionLab/images/book.png new file mode 100644 index 0000000..b85bca3 Binary files /dev/null and b/ImageRecognitionLab/images/book.png differ diff --git a/ImageRecognitionLab/images/coffee_mug.jpg b/ImageRecognitionLab/images/coffee_mug.jpg new file mode 100644 index 0000000..2ea39ad Binary files /dev/null and b/ImageRecognitionLab/images/coffee_mug.jpg differ diff --git a/ImageRecognitionLab/images/laptop.jpg b/ImageRecognitionLab/images/laptop.jpg new file mode 100644 index 0000000..59fa601 Binary files /dev/null and b/ImageRecognitionLab/images/laptop.jpg differ diff --git a/ImageRecognitionLab/images/pill_bottle.png b/ImageRecognitionLab/images/pill_bottle.png new file mode 100644 index 0000000..d541dab Binary files /dev/null and b/ImageRecognitionLab/images/pill_bottle.png differ diff --git a/ImageRecognitionLab/images/readme.md b/ImageRecognitionLab/images/readme.md new file mode 100644 index 0000000..3a3c83a --- /dev/null +++ b/ImageRecognitionLab/images/readme.md @@ -0,0 +1 @@ +Some images that you can use for prediction are added here diff --git a/ImageRecognitionLab/images/smartphone.png b/ImageRecognitionLab/images/smartphone.png new file mode 100644 index 0000000..1669b25 Binary files /dev/null and b/ImageRecognitionLab/images/smartphone.png differ diff --git a/ImageRecognitionLab/src/main/java/com/example/img/ProductRecognitionNewModel.java b/ImageRecognitionLab/src/main/java/com/example/img/ProductRecognitionNewModel.java new file mode 100644 index 0000000..019871c --- /dev/null +++ b/ImageRecognitionLab/src/main/java/com/example/img/ProductRecognitionNewModel.java @@ -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 features = extractImageFeatures(originalImage); + + // Step 3: Classify the image based on features + List 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 extractImageFeatures(BufferedImage image) { + Map 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 classifyImage(Map features, String filename) { + List 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 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; + } + } +} \ No newline at end of file diff --git a/ImageRecognitionLab/src/main/java/com/example/img/ProductRecognitionPreTrainedModel.java b/ImageRecognitionLab/src/main/java/com/example/img/ProductRecognitionPreTrainedModel.java new file mode 100644 index 0000000..70e1eef --- /dev/null +++ b/ImageRecognitionLab/src/main/java/com/example/img/ProductRecognitionPreTrainedModel.java @@ -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 translator = ImageClassificationTranslator.builder() + .addTransform(new Resize(224, 224)) + .addTransform(new ToTensor()) + .optApplySoftmax(true) + .build(); + + // Updated criteria to use explicit model from TorchHub + Criteria criteria = Criteria.builder() + .setTypes(Image.class, Classifications.class) + .optTranslator(translator) + .optArtifactId("resnet") // Use explicit model name + .optEngine("PyTorch") // Specify engine + .build(); + + try (ZooModel model = criteria.loadModel(); + Predictor predictor = model.newPredictor()) { + return predictor.predict(image); + } + } +} \ No newline at end of file diff --git a/ImageRecognitionLab/src/main/resources/application.properties b/ImageRecognitionLab/src/main/resources/application.properties new file mode 100644 index 0000000..d4ccb30 --- /dev/null +++ b/ImageRecognitionLab/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.application.name=img diff --git a/ImageRecognitionLab/src/test/java/com/example/img/ImgApplicationTests.java b/ImageRecognitionLab/src/test/java/com/example/img/ImgApplicationTests.java new file mode 100644 index 0000000..b4e360f --- /dev/null +++ b/ImageRecognitionLab/src/test/java/com/example/img/ImgApplicationTests.java @@ -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() { + } + +} diff --git a/settings.gradle b/settings.gradle index 7e810bd..bf28a8f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,4 +8,5 @@ include 'InventoryManagementSystem' include 'SmartClinicManagementSystem:app' include 'SoftwareDevChatbot' include 'RegressionPredictionLab' -include 'SentimentAnalysisLab' \ No newline at end of file +include 'SentimentAnalysisLab' +include 'ImageRecognitionLab' \ No newline at end of file