001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.demos; 031 032import java.io.File; 033import java.io.IOException; 034import java.util.List; 035 036import org.openimaj.image.DisplayUtilities; 037import org.openimaj.image.FImage; 038import org.openimaj.image.ImageUtilities; 039import org.openimaj.image.connectedcomponent.ConnectedComponentLabeler; 040import org.openimaj.image.pixel.ConnectedComponent; 041import org.openimaj.image.pixel.ConnectedComponent.ConnectMode; 042import org.openimaj.image.processing.convolution.AverageBoxFilter; 043import org.openimaj.image.processing.threshold.OtsuThreshold; 044import org.openimaj.math.geometry.shape.Rectangle; 045 046public class ImgDetector { 047 048 public static void main(String[] args) throws IOException { 049 final FImage img = ImageUtilities 050 .readF(new File( 051 "/Users/jon/Library/Containers/com.apple.mail/Data/Library/Mail Downloads/BD5C21CA-CC93-4C38-A96D-A44E961C5544/in-2.jpg")); 052 053 // blur the image, with more blur in the horizontal direction than 054 // vertical 055 final FImage i1 = img.process(new AverageBoxFilter(40, 10)); 056 057 // numerical issues from the way the box filter is implemented might 058 // mean that there are values slightly bigger than 1, so clip the values 059 // to a maximum of 1. 060 i1.clip(0f, 1f); 061 062 // threshold the image to make it purely black and white 063 i1.processInplace(new OtsuThreshold()); 064 065 // invert the image before input to the ConnectedComponentLabeler 066 i1.inverse(); 067 068 // Apply connected component labelling to find all the "blobs" 069 final ConnectedComponentLabeler ccl = new ConnectedComponentLabeler(ConnectMode.CONNECT_8); 070 final List<ConnectedComponent> ccs = ccl.findComponents(i1); 071 072 // values for the computed bounds of the "graphic" 073 int left = i1.width; 074 int right = 0; 075 int top = i1.height; 076 int bottom = 0; 077 078 // loop through the "blobs" and filter them 079 for (final ConnectedComponent cc : ccs) { 080 final Rectangle bb = cc.calculateRegularBoundingBox(); 081 082 // ignore components that are near the top edge 083 if (bb.y < 0.1 * i1.height) 084 continue; 085 086 // ignore components that are near the right edge 087 if (bb.x + bb.width > 0.9 * i1.width) 088 continue; 089 090 // filter the other components based on their width and the relative 091 // area of the blob to its bounding box (should be ~1 for a text 092 // block) 093 if (bb.width < 0.4 * i1.width || bb.calculateArea() / cc.calculateArea() > 2) { 094 if (bb.x < left) 095 left = (int) bb.x; 096 if (bb.x + bb.width > right) 097 right = (int) (bb.x + bb.width); 098 if (bb.y < top) 099 top = (int) bb.y; 100 if (bb.y + bb.height > bottom) 101 bottom = (int) (bb.y + bb.height); 102 i1.drawShape(bb, 0.5f); 103 } 104 } 105 106 // construct the final bounds rectangle (might want to extend/pad it) 107 final Rectangle bounds = new Rectangle(left, top, right - left, bottom - top); 108 DisplayUtilities.display(img.extractROI(bounds)); 109 } 110}