PageRenderTime 46ms CodeModel.GetById 13ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

/ocr/ocrservice/src/com/googlecode/eyesfree/opticflow/TimestampedFrame.java

http://eyes-free.googlecode.com/
Java | 210 lines | 116 code | 38 blank | 56 comment | 19 complexity | 288cfe683d2292d9377f5eeb4d21a58c MD5 | raw file
  1/*
  2 * Copyright (C) 2011 Google Inc.
  3 *
  4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5 * use this file except in compliance with the License. You may obtain a copy of
  6 * the License at
  7 *
  8 * http://www.apache.org/licenses/LICENSE-2.0
  9 *
 10 * Unless required by applicable law or agreed to in writing, software
 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 13 * License for the specific language governing permissions and limitations under
 14 * the License.
 15 */
 16
 17package com.googlecode.eyesfree.opticflow;
 18
 19import android.util.Log;
 20
 21import com.googlecode.eyesfree.env.Size;
 22import com.googlecode.eyesfree.opticflow.FrameProducer.Frame;
 23import com.googlecode.leptonica.android.Pix;
 24import com.googlecode.leptonica.android.Pixa;
 25import com.googlecode.leptonica.android.ReadFile;
 26
 27/**
 28 * Class for interfacing efficiently with image data, and keeping track of all
 29 * records associated with a frame.
 30 *
 31 * @author alanv@google.com (Alan Viverette)
 32 */
 33public class TimestampedFrame {
 34    private static final String TAG = "TimestampedFrame";
 35
 36    private int threadsLeft;
 37
 38    // For caching PIX created from rawFrameData.
 39    private Pix cachedPix;
 40
 41    // Whether this frame is thought to be blurred. May be null.
 42    private Boolean isBlurred;
 43
 44    // Whether this frame was created while focus was occurring. May be null.
 45    private Boolean takenWhileFocusing;
 46
 47    // The results of text detection.
 48    private Pixa detectedText;
 49
 50    // The FDR value of detected text areas.
 51    private float[] textConfidences;
 52
 53    // The estimated angle for text present in this frame.
 54    // TODO(alanv): Make this a per-Pix setting?
 55    private float angle;
 56
 57    private final Frame originalFrame;
 58
 59    // TODO(andrewharp): Create pool of TimestampedFrames so that used frames
 60    // can be recycled.
 61    protected TimestampedFrame(final Frame originalFrame) {
 62        this.originalFrame = originalFrame;
 63    }
 64
 65    public long getTimestamp() {
 66        return originalFrame.timestamp;
 67    }
 68
 69    public Size getSize() {
 70        return new Size(originalFrame.width, originalFrame.height);
 71    }
 72
 73    public int getWidth() {
 74        return originalFrame.width;
 75    }
 76
 77    public int getHeight() {
 78        return originalFrame.height;
 79    }
 80
 81    public void setDetectedText(Pixa detectedText, float[] textAreaQuality, float angle) {
 82        if (detectedText == null) {
 83            throw new IllegalArgumentException("Detected text must be non-null");
 84        }
 85
 86        this.detectedText = detectedText.copy();
 87        this.textConfidences = textAreaQuality;
 88        this.angle = angle;
 89    }
 90
 91    public Pixa getDetectedText() {
 92        if (detectedText != null) {
 93            return detectedText.copy();
 94        } else {
 95            return null;
 96        }
 97    }
 98
 99    public float[] getTextConfidences() {
100        return textConfidences.clone();
101    }
102
103    public float getAngle() {
104        return angle;
105    }
106
107    public void recycleDetectedText() {
108        if (detectedText != null) {
109            detectedText.recycle();
110            detectedText = null;
111        }
112    }
113
114    /**
115     * @return A Pix containing the data for a PIX representation of this frame.
116     */
117    public synchronized Pix getPixData() {
118        if (cachedPix == null) {
119            cachedPix = ReadFile.readBytes8(
120                    originalFrame.data, originalFrame.width, originalFrame.height);
121        }
122
123        return cachedPix.clone();
124    }
125
126    /**
127     * @return Whether or not rawFrameData is null.
128     */
129    protected synchronized boolean hasRawData() {
130        return originalFrame.data != null;
131    }
132
133    /**
134     * @return The raw frame data. Raw data may have already been released, in
135     *         which case an error is logged.
136     */
137    public synchronized byte[] getRawData() {
138        if (!hasRawData()) {
139            Log.e(TAG, "Frame data for frame is no longer available.");
140        }
141        return originalFrame.data;
142    }
143
144    /**
145     * Raw frame data is expensive to keep around, so we need to provide a way
146     * to remove it from this frame after the smaller JPEG is created.
147     *
148     * @return The byte[] this frame was holding.
149     */
150    protected synchronized byte[] clearRawData() {
151        final byte[] tmpData = getRawData(); // So we get the implicit check.
152        originalFrame.recycle();
153        // Unblock any threads that are wait()ing in releaesBitmap(true).
154        notify();
155        return tmpData;
156    }
157
158    public boolean isBlurred() {
159        if (isBlurred == null) {
160            Log.w(TAG, "isBlurred() called without value having been set!");
161
162            // If focusing we can assume it's blurred, otherwise default to
163            // unblurred.
164            return takenWhileFocusing();
165        }
166
167        return isBlurred;
168    }
169
170    public void setBlurred(final boolean blurred) {
171        if (isBlurred != null) {
172            Log.w(TAG, "Blurred already set!");
173        }
174
175        isBlurred = blurred;
176    }
177
178    public void setTakenWhileFocusing(final boolean takenWhileFocusing) {
179        this.takenWhileFocusing = takenWhileFocusing;
180    }
181
182    public boolean takenWhileFocusing() {
183        if (takenWhileFocusing == null) {
184            return false;
185        }
186        return takenWhileFocusing.booleanValue();
187    }
188
189    /**
190     * Used by a ProcessingThread to signify that it's done processing this
191     * frame.
192     */
193    public void threadDone() {
194        --threadsLeft;
195        if (threadsLeft < 0) {
196            Log.w(TAG, "Negative number of threads remaining.");
197        }
198    }
199
200    /**
201     * @return true iff all threads have finished processing this frame.
202     */
203    public boolean allThreadsDone() {
204        return threadsLeft == 0;
205    }
206
207    public void threadStart() {
208        ++threadsLeft;
209    }
210}