/ocr/worldreader/src/com/google/marvin/worldreader/RecognizeActivity.java
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}