PageRenderTime 36ms CodeModel.GetById 13ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 1ms

/ocr/worldreader/src/com/google/marvin/worldreader/RecognizeActivity.java

http://eyes-free.googlecode.com/
Java | 320 lines | 238 code | 47 blank | 35 comment | 31 complexity | b1dfffe39fb5d1d54cc64b851d34370d MD5 | raw file
  1/*
  2 * Copyright (C) 2009 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 */
 16package com.google.marvin.worldreader;
 17
 18import android.app.Activity;
 19import android.content.Context;
 20import android.content.Intent;
 21import android.graphics.Bitmap;
 22import android.graphics.BitmapFactory;
 23import android.os.Bundle;
 24import android.os.Handler;
 25import android.os.Message;
 26import android.speech.tts.TextToSpeech;
 27import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener;
 28import android.util.Log;
 29import android.view.Display;
 30import android.view.KeyEvent;
 31import android.view.View;
 32import android.view.WindowManager;
 33import android.widget.Button;
 34import android.widget.ImageView;
 35import android.widget.ProgressBar;
 36import android.widget.TextView;
 37
 38import com.android.ocr.client.Config;
 39import com.android.ocr.client.Intents;
 40import com.android.ocr.client.Ocr;
 41import com.android.ocr.client.Result;
 42import com.android.ocr.client.StatusMonitor;
 43
 44import java.util.HashMap;
 45
 46/**
 47 * This activity runs text recognition and displays bounding box results. If the
 48 * OCR service fails or is missing, this activity will return null.
 49 * 
 50 * Modified from com.google.marvin.ocr.intent.RecognizeActivity to speak results
 51 * out loud.
 52 * 
 53 * @author alanv@google.com (Alan Viverette)
 54 */
 55public class RecognizeActivity extends Activity implements Button.OnClickListener,
 56    OnUtteranceCompletedListener {
 57  private static final String TAG = "RecognizeActivity";
 58
 59  private static final int ACTION_INITIALIZED = 0;
 60  private static final int ACTION_RESULT = 1;
 61  private static final int ACTION_RECOGNIZED = 2;
 62  private static final int ACTION_UPDATE = 3;
 63
 64  private Ocr mOcr;
 65  private Bitmap mBitmap;
 66  private ImageView mImageView;
 67  private RectsView mOverlayView;
 68  private Button mCancel;
 69  private Config mConfig;
 70  private ProgressBar mProgress;
 71  private StatusMonitor mStatusMonitor;
 72  private TextToSpeech mTts;
 73  private boolean mOcrBusy;
 74
 75  private final Handler mHandler = new Handler() {
 76    @Override
 77    public void handleMessage(Message message) {
 78      switch (message.what) {
 79        case ACTION_INITIALIZED: {
 80          if (message.arg1 == Ocr.STATUS_SUCCESS) {
 81            processConfig();
 82          } else {
 83            Log.e(TAG, "Ocr initialization failed");
 84            processResults(null);
 85          }
 86          break;
 87        }
 88        case ACTION_RESULT: {
 89          if (message.obj == null || message.obj instanceof Result) {
 90            processResult((Result) message.obj);
 91          }
 92          break;
 93        }
 94        case ACTION_RECOGNIZED: {
 95          mStatusMonitor.release();
 96
 97          if (message.obj == null || message.obj instanceof Result[]) {
 98            processResults((Result[]) message.obj);
 99          }
100          break;
101        }
102        case ACTION_UPDATE: {
103          updateProgress((String) message.obj, message.arg1, message.arg2);
104          break;
105        }
106      }
107    }
108  };
109
110  @Override
111  public void onCreate(Bundle savedInstanceState) {
112    super.onCreate(savedInstanceState);
113
114    setContentView(R.layout.recognize);
115
116    mTts = ReaderActivity.mTts;
117    mTts.setOnUtteranceCompletedListener(this);
118
119    mProgress = (ProgressBar) findViewById(R.id.progress);
120    mProgress.setIndeterminate(false);
121
122    mImageView = (ImageView) findViewById(R.id.image);
123    mOverlayView = (RectsView) findViewById(R.id.overlay);
124    mCancel = (Button) findViewById(R.id.cancelOcr);
125    mCancel.setOnClickListener(this);
126
127    mConfig = (Config) getIntent().getParcelableExtra(Intents.Recognize.CONFIG);
128
129    setBackground();
130
131    Ocr.InitCallback onInit = new Ocr.InitCallback() {
132      @Override
133      public void onInitialized(int status) {
134        Message msg = mHandler.obtainMessage(ACTION_INITIALIZED, status, 0);
135        msg.sendToTarget();
136      }
137    };
138
139    mOcr = new Ocr(this, onInit);
140    mStatusMonitor = new StatusMonitor(mOcr, mHandler, ACTION_UPDATE, 500L);
141  }
142
143  @Override
144  public boolean onKeyDown(int keyCode, KeyEvent event) {
145    switch (keyCode) {
146      case KeyEvent.KEYCODE_BACK: {
147        if (mOcrBusy) {
148          mOcr.stop();
149          return true;
150        } else {
151          mTts.stop();
152        }
153        break;
154      }
155    }
156
157    return false;
158  }
159
160  @Override
161  public void onDestroy() {
162    mBitmap.recycle();
163    mOcr.release();
164    mTts.setOnUtteranceCompletedListener(null);
165    mTts.stop();
166
167    super.onDestroy();
168  }
169
170  @Override
171  public void onClick(View v) {
172    if (v == mCancel) {
173      KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
174      onKeyDown(KeyEvent.KEYCODE_BACK, event);
175    }
176  }
177
178  private void processConfig() {
179    Log.i(TAG, "Processing supplied configuration...");
180
181    Ocr.CompletionCallback onCompleted = new Ocr.CompletionCallback() {
182      @Override
183      public void onCompleted(Result[] results) {
184        Message msg = mHandler.obtainMessage(ACTION_RECOGNIZED, results);
185        msg.sendToTarget();
186      }
187    };
188
189    Ocr.ResultCallback onResult = new Ocr.ResultCallback() {
190      @Override
191      public void onResult(Result result) {
192        Message msg = mHandler.obtainMessage(ACTION_RESULT, result);
193        msg.sendToTarget();
194      }
195    };
196
197    if (!mOcr.recognizeText(mConfig, onResult, onCompleted)) {
198      Log.e(TAG, "Text recognition call failed");
199
200      onCompleted.onCompleted(null);
201    } else {
202      mOcrBusy = true;
203      mStatusMonitor.start();
204    }
205  }
206
207  private void processResults(Result[] results) {
208    if (results == null) {
209      Log.e(TAG, "Received null results");
210      setResult(RESULT_CANCELED);
211    } else {
212      Intent result = new Intent();
213      result.setAction(Intents.Recognize.ACTION);
214      result.putExtra(Intents.Recognize.RESULTS, results);
215
216      setResult(RESULT_OK, result);
217      Log.e(TAG, "Set OUT_RESULTS to array with length " + results.length);
218      for (Result res : results) {
219        Log.e(TAG, "    Result: " + res.getString());
220      }
221      Log.e(TAG, "Confirm contains " + result.getExtras().size() + " extras");
222    }
223
224    HashMap<String, String> params = new HashMap<String, String>();
225    params.put("utteranceId", TAG);
226    params.put("utterance_id", TAG);
227    params.put("utterance-id", TAG);
228
229    mOcrBusy = false;
230    mTts.speak("end", TextToSpeech.QUEUE_ADD, params);
231  }
232
233  /**
234   * Speak the text and draw the bounding box of a single result.
235   * 
236   * @param result
237   */
238  private void processResult(Result result) {
239    String str = postProcess(result.getString());
240    mTts.speak(str, TextToSpeech.QUEUE_ADD, null);
241
242    mOverlayView.addRect(result.getBounds());
243  }
244
245  private void setBackground() {
246    byte[] image = mConfig.image;
247    WindowManager manager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
248    Display display = manager.getDefaultDisplay();
249    int width = display.getWidth();
250    int scale = Integer.highestOneBit(mConfig.width / width);
251
252    BitmapFactory.Options opts = new BitmapFactory.Options();
253    opts.inSampleSize = Math.max(1, scale);
254
255    mBitmap = BitmapFactory.decodeByteArray(image, 0, image.length, opts);
256    mImageView.setImageBitmap(mBitmap);
257
258    mOverlayView.setScaling(mConfig.width, mConfig.height, display.getWidth(), display.getHeight());
259  }
260
261  private void updateProgress(String status, int current, int max) {
262    if (current < 0 || max <= 0) {
263      return;
264    }
265
266    ProgressBar progress = (ProgressBar) findViewById(R.id.progress);
267    TextView txtPercent = (TextView) findViewById(R.id.progress_percent);
268    TextView txtNumber = (TextView) findViewById(R.id.progress_number);
269
270    int intPercent = 100 * current / max;
271
272    String strPercent = getString(R.string.percent, intPercent);
273    String strNumber = getString(R.string.ratio, current, max);
274
275    progress.setMax(max);
276    progress.setProgress(current);
277    txtPercent.setText(strPercent);
278    txtNumber.setText(strNumber);
279
280    progress.postInvalidate();
281    txtPercent.postInvalidate();
282    txtNumber.postInvalidate();
283  }
284
285  /**
286   * Removes words that consist of more than 1/3 non-word characters.
287   * 
288   * @param text the text to process
289   * @return the processed text
290   */
291  private String postProcess(String text) {
292    String[] input = text.split(" ");
293    String output = "";
294
295    for (int i = 0; i < input.length; i++) {
296      if (input[i].length() <= 0) {
297        continue;
298      }
299      int letterCount = 0;
300      for (int j = 0; j < input[i].length(); j++) {
301        char chr = input[i].charAt(j);
302        if (chr == '\n' || Character.isLetterOrDigit(chr)) {
303          letterCount++;
304        }
305      }
306      if (10 * letterCount / input[i].length() > 6) {
307        output += input[i] + " ";
308      }
309    }
310
311    return output;
312  }
313
314  @Override
315  public void onUtteranceCompleted(String utteranceId) {
316    if (utteranceId.equals(TAG)) {
317      finish();
318    }
319  }
320}