1 /**
2 * Copyright (c) 2011, The University of Southampton and the individual contributors.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * * Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * * Neither the name of the University of Southampton nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 package org.openimaj.demos;
31
32 import java.io.File;
33 import java.io.IOException;
34 import java.util.List;
35
36 import org.openimaj.image.DisplayUtilities;
37 import org.openimaj.image.FImage;
38 import org.openimaj.image.ImageUtilities;
39 import org.openimaj.image.connectedcomponent.ConnectedComponentLabeler;
40 import org.openimaj.image.pixel.ConnectedComponent;
41 import org.openimaj.image.pixel.ConnectedComponent.ConnectMode;
42 import org.openimaj.image.processing.convolution.AverageBoxFilter;
43 import org.openimaj.image.processing.threshold.OtsuThreshold;
44 import org.openimaj.math.geometry.shape.Rectangle;
45
46 public class ImgDetector {
47
48 public static void main(String[] args) throws IOException {
49 final FImage img = ImageUtilities
50 .readF(new File(
51 "/Users/jon/Library/Containers/com.apple.mail/Data/Library/Mail Downloads/BD5C21CA-CC93-4C38-A96D-A44E961C5544/in-2.jpg"));
52
53 // blur the image, with more blur in the horizontal direction than
54 // vertical
55 final FImage i1 = img.process(new AverageBoxFilter(40, 10));
56
57 // numerical issues from the way the box filter is implemented might
58 // mean that there are values slightly bigger than 1, so clip the values
59 // to a maximum of 1.
60 i1.clip(0f, 1f);
61
62 // threshold the image to make it purely black and white
63 i1.processInplace(new OtsuThreshold());
64
65 // invert the image before input to the ConnectedComponentLabeler
66 i1.inverse();
67
68 // Apply connected component labelling to find all the "blobs"
69 final ConnectedComponentLabeler ccl = new ConnectedComponentLabeler(ConnectMode.CONNECT_8);
70 final List<ConnectedComponent> ccs = ccl.findComponents(i1);
71
72 // values for the computed bounds of the "graphic"
73 int left = i1.width;
74 int right = 0;
75 int top = i1.height;
76 int bottom = 0;
77
78 // loop through the "blobs" and filter them
79 for (final ConnectedComponent cc : ccs) {
80 final Rectangle bb = cc.calculateRegularBoundingBox();
81
82 // ignore components that are near the top edge
83 if (bb.y < 0.1 * i1.height)
84 continue;
85
86 // ignore components that are near the right edge
87 if (bb.x + bb.width > 0.9 * i1.width)
88 continue;
89
90 // filter the other components based on their width and the relative
91 // area of the blob to its bounding box (should be ~1 for a text
92 // block)
93 if (bb.width < 0.4 * i1.width || bb.calculateArea() / cc.calculateArea() > 2) {
94 if (bb.x < left)
95 left = (int) bb.x;
96 if (bb.x + bb.width > right)
97 right = (int) (bb.x + bb.width);
98 if (bb.y < top)
99 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 }