diff --git a/ALPR/ALPR.java b/ALPR/ALPR.java new file mode 100644 index 0000000..c59e82b --- /dev/null +++ b/ALPR/ALPR.java @@ -0,0 +1,408 @@ +// Automatic License Plate Recognition (ALPR) +// (c) 2023, Joe James + +/******************************************************************************* + * This Automatic License Plate Reader program is mainly intended to + * accompany my series of YouTube tutorial videos here, + * https://www.youtube.com/user/joejamesusa and is mainly + * intended for educational purposes. You are invited to subscribe to my + * video channel, and to download and use any code in this Java + * repository, according to the MIT License. Feel free to post any comments + * on my YouTube channel. + * + * ****************************************************************************/ + +import java.util.*; +import java.awt.*; +import java.awt.image.*; +import java.awt.geom.AffineTransform; +import java.io.*; +import javax.imageio.ImageIO; +import javax.swing.*; +import java.util.stream.*; +import java.lang.Math; + +public class ALPR { + // Penitentiary Gothic font, 20x43 pix = 860 pixels + int[] CHARSIZE = {20, 43}; + int NUMPIXELS = CHARSIZE[0] * CHARSIZE[1]; + ArrayList trainLabels = new ArrayList<>(Arrays.asList("A","B","C","D","E","F","G","H","I","J","K","L","M", + "N","O","P","Q","R","S","T","U","V","W","X","Y","Z","0","1","2","3","4","5","6","7","8","9")); + ArrayList trainData = new ArrayList<>(trainLabels.size()); + + public static void main(String[] args) { + ALPR alpr = new ALPR(); + File[] files = new File[4]; + files[0] = new File("Training Data/letters-1 image.png"); + files[1] = new File("Training Data/letters-2 image.png"); + files[2] = new File("Training Data/letters-3 image.png"); + files[3] = new File("Training Data/numbers image.png"); + alpr.train(files); + + //File file = new File("License Plate Photos/ca_aug2012.png"); + //File file = new File("License Plate Photos/ca_12.jpeg"); + File file = new File("License Plate Photos/ca_10.jpeg"); + //File file = new File("License Plate Photos/ca2004.jpg"); + //File file = new File("License Plate Photos/ca2005.jpg"); + //File file = new File("License Plate Photos/ca2006.jpg"); + //File file = new File("License Plate Photos/ca_blue_1.jpeg"); + //File file = new File("License Plate Photos/tx_4.jpeg"); + //File file = new File("License Plate Photos/ny_1.jpeg"); + //File file = new File("License Plate Photos/fl_1.jpeg"); + alpr.readPlate(file); + } + + public void readPlate(File file) { + System.out.println("Loading file."); + BufferedImage img = null; + int height1 = 200; + ArrayList testData = new ArrayList<>(); + try { img = ImageIO.read(file); } + catch (IOException e) { e.printStackTrace(System.out); } + + if (img != null) { + display(img); + img = toGrayScale(img); + display(img); + img = getScaledImage(img, height1); + + // Crop out top and bottom margins + int[] vertBounds = getTopBottom(img); + img = img.getSubimage(0, vertBounds[0], img.getWidth(), vertBounds[1]-vertBounds[0]); + + // Scale image to CHARSIZE height + img = getScaledImage(img, CHARSIZE[1]); + System.out.println(" Scaled image: " + img.getHeight() + "x" + img.getWidth()); + display(img); + + // boost contrast + img = boostContrast(img); + + ArrayList edges = getEdges(img); + System.out.println(" Found edges: " + edges); + /*display(img.getSubimage(edges.get(0)+2, 0, CHARSIZE[0], img.getHeight())); + display(img.getSubimage(edges.get(1)+2, 0, CHARSIZE[0], img.getHeight())); + display(img.getSubimage(edges.get(2)+2, 0, CHARSIZE[0], img.getHeight())); + display(img.getSubimage(edges.get(3)+2, 0, CHARSIZE[0], img.getHeight())); + display(img.getSubimage(edges.get(4)+2, 0, CHARSIZE[0], img.getHeight())); + display(img.getSubimage(edges.get(5)+2, 0, CHARSIZE[0], img.getHeight())); + display(img.getSubimage(edges.get(6)+2, 0, CHARSIZE[0], img.getHeight()));*/ + + // add character data to ArrayList for comparisons to trainData + testData = imgToArray(img, testData, edges); + + // identify characters in testData + String plateNum = identify(testData); + System.out.println(plateNum); + } + } + + // receives an image of a plate, splits it into digits + public void train(File[] files) { + BufferedImage img = null; + + for (int i=0; i edges = getEdges(img); + + // add grayscale data for each character to training data set + trainData = imgToArray(img, trainData, edges); + + //int[] intArray = Arrays.stream(trainData.get(trainData.size()-1)).mapToInt(Integer::intValue).toArray(); + //display(intArray, CHARSIZE[0], CHARSIZE[1]); + } + } + // add a few hard-coded chars to training data + addMoreTrainingData(); + + System.out.println(trainData.size() + " characters loaded."); + } + + // convert imageto grayscale + public BufferedImage toGrayScale(BufferedImage img) { + System.out.println(" Converting to GrayScale."); + BufferedImage grayImage = new BufferedImage( + img.getWidth(), img.getHeight(), BufferedImage.TYPE_BYTE_GRAY); + Graphics g = grayImage.getGraphics(); + g.drawImage(img, 0, 0, null); + g.dispose(); + return grayImage; + } + + // display image in a JPanel popup + public void display (BufferedImage img) { + //System.out.println(" Displaying image."); + JFrame frame = new JFrame(); + JLabel label = new JLabel(); + frame = new JFrame(); + frame.setSize(img.getWidth(), img.getHeight()); + label.setIcon(new ImageIcon(img)); + frame.getContentPane().add(label, BorderLayout.CENTER); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frame.pack(); + frame.setVisible(true); + } + + // display image in a JPanel popup, from int array + private void display(int[] pixels, int width, int height) { + System.out.println(" Printing image for array length: " + pixels.length + ", " + width + "x" + height); + BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); + WritableRaster raster = img.getRaster(); + raster.setPixels(0, 0, width, height, pixels); + display(img); + } + + // scale image + private BufferedImage getScaledImage (BufferedImage img, int newHeight) { + System.out.println(" Scaling image."); + double scaleFactor = (double) newHeight/img.getHeight(); + BufferedImage scaledImg = new BufferedImage( + (int)(scaleFactor*img.getWidth()), newHeight, BufferedImage.TYPE_BYTE_GRAY); + AffineTransform at = new AffineTransform(); + at.scale(scaleFactor, scaleFactor); + AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR); + return scaleOp.filter(img, scaledImg); + } + + // convert grayscale image to BW + private BufferedImage boostContrast(BufferedImage img) { + // compute average pixel darkness + int avg = 0; + for (int y=0; yavg) + p = (255<<24) | (255<<16) | (255<<8) | 255; + else + p = (255<<24) | (0<<16) | (0<<8) | 0; + img.setRGB(x, y, p); + } + } + return img; + } + + private Integer[] boostContrast(Integer[] data) { + // compute average pixel darkness + int avg = 0; + for (int i=0; iavg) + data[i] = 255; + else + data[i] = 0; + } + //int[] bwChar = Arrays.stream(data).mapToInt(Integer::intValue).toArray(); + //display(bwChar, CHARSIZE[0], CHARSIZE[1]); + return data; + } + + // use trainData to identify each character in testData + private String identify(ArrayList testData) { + System.out.println(" Identifying characters in plate."); + String plateNum = ""; + for (Integer[] testChar : testData) { + int[] distances = new int[trainData.size()]; + for (int t=0; t50; i--) { + if (deltaGray[i] > 5) { + vertBounds[0] = i-2; + break; + } + } + for (int i=120; i<180; i++) { + if (deltaGray[i] < -5) { + vertBounds[1] = i+2; + break; + } + } + System.out.println("Vert bounds: " + vertBounds[0] + " " + vertBounds[1]); + return vertBounds; + } + + // add grayscale data for each character to ArrayList + private ArrayList imgToArray (BufferedImage img, ArrayList data, ArrayList edges) { + for (Integer e : edges) { + data.add(new Integer[NUMPIXELS]); + for (int j=0; j getEdges(BufferedImage img) { + System.out.println(" Getting edges between characters."); + // Locate whitespace delimiters between characters (left & rt bounds for each character) + int[] colSums = new int[img.getWidth()]; + for (int y=0; y edges = new ArrayList<>(); + int col = 0; + while (col 250*CHARSIZE[1])) { + whiteCols += 1; + } + if ((whiteCols > 1) & (col+whiteCols+CHARSIZE[0] < img.getWidth())) + edges.add((int)(col + whiteCols -1)); + col += whiteCols + 1; + } + //System.out.println(edges); + + return edges; + } + +} + diff --git a/ALPR/License Plate Photos/ca2004.jpg b/ALPR/License Plate Photos/ca2004.jpg new file mode 100644 index 0000000..7deed82 Binary files /dev/null and b/ALPR/License Plate Photos/ca2004.jpg differ diff --git a/ALPR/License Plate Photos/ca2005.jpg b/ALPR/License Plate Photos/ca2005.jpg new file mode 100644 index 0000000..477fded Binary files /dev/null and b/ALPR/License Plate Photos/ca2005.jpg differ diff --git a/ALPR/License Plate Photos/ca2006.jpg b/ALPR/License Plate Photos/ca2006.jpg new file mode 100644 index 0000000..d07ccb7 Binary files /dev/null and b/ALPR/License Plate Photos/ca2006.jpg differ diff --git a/ALPR/License Plate Photos/ca_10.jpeg b/ALPR/License Plate Photos/ca_10.jpeg new file mode 100644 index 0000000..342897e Binary files /dev/null and b/ALPR/License Plate Photos/ca_10.jpeg differ diff --git a/ALPR/License Plate Photos/ca_12.jpeg b/ALPR/License Plate Photos/ca_12.jpeg new file mode 100644 index 0000000..afd0d73 Binary files /dev/null and b/ALPR/License Plate Photos/ca_12.jpeg differ diff --git a/ALPR/License Plate Photos/ca_aug2012.png b/ALPR/License Plate Photos/ca_aug2012.png new file mode 100644 index 0000000..c9b2b2d Binary files /dev/null and b/ALPR/License Plate Photos/ca_aug2012.png differ diff --git a/ALPR/License Plate Photos/fl_1.jpeg b/ALPR/License Plate Photos/fl_1.jpeg new file mode 100644 index 0000000..a9f2ed4 Binary files /dev/null and b/ALPR/License Plate Photos/fl_1.jpeg differ diff --git a/ALPR/License Plate Photos/ny_1.jpeg b/ALPR/License Plate Photos/ny_1.jpeg new file mode 100644 index 0000000..b0bb269 Binary files /dev/null and b/ALPR/License Plate Photos/ny_1.jpeg differ diff --git a/ALPR/License Plate Photos/tx_4.jpeg b/ALPR/License Plate Photos/tx_4.jpeg new file mode 100644 index 0000000..54b90f2 Binary files /dev/null and b/ALPR/License Plate Photos/tx_4.jpeg differ diff --git a/ALPR/Training Data/letters-1 image.png b/ALPR/Training Data/letters-1 image.png new file mode 100644 index 0000000..e9089a7 Binary files /dev/null and b/ALPR/Training Data/letters-1 image.png differ diff --git a/ALPR/Training Data/letters-2 image.png b/ALPR/Training Data/letters-2 image.png new file mode 100644 index 0000000..f76ee7d Binary files /dev/null and b/ALPR/Training Data/letters-2 image.png differ diff --git a/ALPR/Training Data/letters-3 image.png b/ALPR/Training Data/letters-3 image.png new file mode 100644 index 0000000..5e1c5ef Binary files /dev/null and b/ALPR/Training Data/letters-3 image.png differ diff --git a/ALPR/Training Data/numbers image.png b/ALPR/Training Data/numbers image.png new file mode 100644 index 0000000..9a56919 Binary files /dev/null and b/ALPR/Training Data/numbers image.png differ diff --git a/EscapeNestedLoops.java b/EscapeNestedLoops.java new file mode 100644 index 0000000..24546bd --- /dev/null +++ b/EscapeNestedLoops.java @@ -0,0 +1,26 @@ +// Java - How to Break out of Nested For Loops + +class EscapeNestedLoops { + public static void main(String[] args) { + + for(int x=0; x<8; x++) { + for(int y=1; y<4; y++) { + System.out.println(x + " " + y + " " + x*y); + if(x * y > 5) + break; + } + } + + System.out.println(" "); + + xLoop: + for(int x=0; x<8; x++) { + for(int y=1; y<4; y++) { + System.out.println(x + " " + y + " " + x*y); + if(x * y > 5) + break xLoop; + } + } + + } +} \ No newline at end of file diff --git a/Image Filters/ImageFilter.java b/Image Filters/ImageFilter.java new file mode 100644 index 0000000..4b31afe --- /dev/null +++ b/Image Filters/ImageFilter.java @@ -0,0 +1,281 @@ +/******************************************************************************* + * Filter Algorithms for Java BufferedImage + * (c) 2023, Joe James + * + * This program loads an image file. It has methods to: + * - display the image in a JPanel popup window; + * - convert the image to grayscale; + * - scale a grayscale image to a different size; + * - pixelate a grayscale image; + * - apply a Gaussian blur to a grayscale image; + * - detect edges of a grayscale image; + * - brighten a color image. + * + * These files are mainly intended to accompany my series of YouTube tutorial + * videos here, https://www.youtube.com/user/joejamesusa and are mainly + * intended for educational purposes. You are invited to subscribe to my + * video channel, and to download and use any code in this Java + * repository, according to the MIT License. Feel free to post any comments + * on my YouTube channel. + * + * ****************************************************************************/ + +import java.util.*; +import java.awt.*; +import java.awt.image.*; +import java.io.*; +import javax.imageio.ImageIO; +import javax.swing.*; +import java.awt.geom.AffineTransform; + +public class ImageFilter { + + public static void main(String[] args) { + File file = new File("photo.png"); + //File file = new File("License Plate Photos/ca_10.jpeg"); + BufferedImage img = null; + + try { img = ImageIO.read(file); } + catch (IOException e) { e.printStackTrace(System.out); } + + if (img != null) { + display(img); + //img = brighten(img); + img = toGrayScale(img); + //img = toGrayScale2(img); + //display(img); + //img = pixelate(img); + //img = pixelate2(img, 3); + //img = resize(img, 150); + //img = blur(img); + img = blur(blur(img)); + img = heavyblur(img); + img = detectEdges(img); + display(img); + } + } + + // display image in a JPanel popup + public static void display (BufferedImage img) { + System.out.println(" Displaying image."); + JFrame frame = new JFrame(); + JLabel label = new JLabel(); + frame.setSize(img.getWidth(), img.getHeight()); + label.setIcon(new ImageIcon(img)); + frame.getContentPane().add(label, BorderLayout.CENTER); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frame.pack(); + frame.setVisible(true); + } + + // convert image to grayscale + public static BufferedImage toGrayScale (BufferedImage img) { + System.out.println(" Converting to GrayScale."); + BufferedImage grayImage = new BufferedImage( + img.getWidth(), img.getHeight(), BufferedImage.TYPE_BYTE_GRAY); + Graphics g = grayImage.getGraphics(); + g.drawImage(img, 0, 0, null); + g.dispose(); + return grayImage; + } + + public static BufferedImage toGrayScale2 (BufferedImage img) { + System.out.println(" Converting to GrayScale2."); + BufferedImage grayImage = new BufferedImage( + img.getWidth(), img.getHeight(), BufferedImage.TYPE_BYTE_GRAY); + int rgb=0, r=0, g=0, b=0; + for (int y=0; y> 16) & 0xFF); + g = ((rgb >> 8) & 0xFF); + b = (rgb & 0xFF); + rgb = (int)((r+g+b)/3); + //rgb = (int)(0.299 * r + 0.587 * g + 0.114 * b); + rgb = (255<<24) | (rgb<<16) | (rgb<<8) | rgb; + grayImage.setRGB(x,y,rgb); + } + } + return grayImage; + } + + // apply 2x2 pixelation to a grayscale image + public static BufferedImage pixelate (BufferedImage img) { + BufferedImage pixImg = new BufferedImage( + img.getWidth(), img.getHeight(), BufferedImage.TYPE_BYTE_GRAY); + int pix = 0, p=0; + for (int y=0; y threshold) + p = (255<<24) | (255<<16) | (255<<8) | 255; + else + p = (255<<24) | (0<<16) | (0<<8) | 0; + edgeImg.setRGB(x,y,p); + } + } + return edgeImg; + } + + // brighten color image by a percentage + public static BufferedImage brighten (BufferedImage img, int percentage) { + int r=0, g=0, b=0, rgb=0, p=0; + int amount = (int)(percentage * 255 / 100); // rgb scale is 0-255, so 255 is 100% + BufferedImage newImage = new BufferedImage( + img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB); + for (int y=0; y> 16) & 0xFF) + amount; + g = ((rgb >> 8) & 0xFF) + amount; + b = (rgb & 0xFF) + amount; + if (r>255) r=255; + if (g>255) g=255; + if (b>255) b=255; + p = (255<<24) | (r<<16) | (g<<8) | b; + newImage.setRGB(x,y,p); + } + } + return newImage; + } + +} + + + + + + + + + + + diff --git a/ListToArray.java b/ListToArray.java new file mode 100644 index 0000000..f78124a --- /dev/null +++ b/ListToArray.java @@ -0,0 +1,45 @@ +// Java: convert ArrayList to String[] +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.*; + +class ListToArray { + public static void main(String[] args) { + // create Array + String[] array = {"Bugatti", "Ferarri", "Lamborghini", "Rolls Royce"}; + + // 3 ways to print Array + System.out.println(Arrays.toString(array)); + + for(String s : array) { + System.out.print(s + ", "); + } + System.out.println(); + + Stream.of(array) + .forEach(System.out::println); + + // 2 ways to convert Array to ArrayList + List arrayList = new ArrayList<>(Arrays.asList(array)); + System.out.println("arrayList: " + arrayList); + + List arrayList2 = new ArrayList<>(List.of(array)); + System.out.println("arrayList2: " + arrayList2); + + // convert ArrayList to Array + String[] array2 = arrayList.toArray(new String[0]); + + // print Array + Stream.of(array2) + .forEach(System.out::println); + + } +} + + + + + + + diff --git a/MapFunctions.java b/MapFunctions.java new file mode 100644 index 0000000..0d17ff8 --- /dev/null +++ b/MapFunctions.java @@ -0,0 +1,71 @@ +// Java HashMap +// Joe James 2023 + +import java.util.Map; +import java.util.HashMap; +import java.util.Map.Entry; +import java.util.stream.*; + +class MapFunctions { + public static void main (String[] args) { + // 1. Create a HashMap, add kv pairs + Map ages = new HashMap(); + // OR, to initialize capaacity, + // Map ages = new HashMap(100); + ages.put("Avni",11); + ages.put("Bing", 12); + ages.put("Cassie", 13); + ages.put("Devarshi", 14); + System.out.println(ages); + + // 2. Get an item from the map + String person = "Cassie"; + System.out.println(person + " : " + ages.get(person)); + System.out.println("Frank" + " : " + ages.getOrDefault("Frank", 0)); + + // 3. Check for membership + System.out.println("Contains key Avni?: " + ages.containsKey("Avni")); + System.out.println("Contains value 23?: " + ages.containsValue(23)); + + // 4. Remove an item from the map + ages.remove("Bing"); + System.out.println(ages); + ages.remove("Devarshi", 41); + System.out.println(ages); + + // 5. Get count of items in map + System.out.println("Num Items = " + ages.size()); + + // 6. Remove all items from map + ages.clear(); + System.out.println("Empty map? " + ages.isEmpty()); + ages.put("Elena", 15); + ages.put("Frank", 16); + System.out.println(ages); + + // 7. Conditional add & replace + ages.putIfAbsent("George", 23); + ages.putIfAbsent("Elena", 5); + System.out.println(ages); + ages.replace("George", 23, 17); + ages.replace("George", 44, 55); + System.out.println(ages); + + // 8. Get collection of Values + System.out.println(ages.values()); + + // 9. Iterate keys using enhanced for loop + for (String key : ages.keySet()) { + System.out.println(key + " : " + ages.get(key)); + } + + // 10. Iterate KV pairs using enhanced for loop + for (Map.Entry pair : ages.entrySet()) { + System.out.println(pair.getKey() + " : " + pair.getValue()); + } + + // 11. Iterate KV pairs using Java 8 Stream API + ages.entrySet().stream().forEach(pair -> System.out.println(pair.getKey() + " : " + pair.getValue())); + + } +} \ No newline at end of file diff --git a/SplitString.java b/SplitString.java new file mode 100644 index 0000000..6f5a4fe --- /dev/null +++ b/SplitString.java @@ -0,0 +1,35 @@ +// Java: Split a String at char +import java.util.Arrays; + +class SplitString { + + public static void main(String[] args) { + String s = "My dog ate my homework; Can I turn it in tomorrow?"; + + String[] ss = s.split(" "); + System.out.println(Arrays.toString(ss)); + + ss = s.split(";"); + System.out.println(Arrays.toString(ss)); + + // you must escape special chars because the split parameter is a regex + // special chars include \ . + ^ $ | ? * ( ) [ { + String t = "54.25-128.17"; + String[] tt = t.split("\\."); + System.out.println(Arrays.toString(tt)); + + // include multiple split chars inside brackets + tt = t.split("[.-]"); + System.out.println(Arrays.toString(tt)); + + } +} + + + + + + + + + diff --git a/StringToInt.java b/StringToInt.java new file mode 100644 index 0000000..adbf9a9 --- /dev/null +++ b/StringToInt.java @@ -0,0 +1,26 @@ +// Java - Convert String to an Int + +class StringToInt { + public static void main(String[] args) { + String s = "222"; + int i; + Integer integer; + + // returns an int + i = Integer.parseInt(s); + System.out.println(i + 1); + + // returns an Integer + integer = Integer.valueOf(s); + System.out.println(integer + 2); + + // Best Practice: safely returns an Integer + try { + integer = Integer.valueOf(s); + } catch (NumberFormatException e) { + integer = 0; + } + System.out.println(integer + 3); + } + +} \ No newline at end of file