Java tutorial
/*---------------------------------------------------------------------------- WhiteBoardCorrection This code is part of the following publication and was subject to peer review: "WhiteBoardCorrection" by Nekomeshi Copyright (c) Nekomeshi <Nekomeshi312@gmail.com> This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. ----------------------------------------------------------------------------*/ package com.nekomeshi312.whiteboardcorrection; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import org.opencv.android.Utils; import org.opencv.calib3d.Calib3d; import org.opencv.core.Core; import org.opencv.core.CvType; import org.opencv.core.Mat; import org.opencv.core.MatOfPoint2f; import org.opencv.core.Point; import org.opencv.core.Scalar; import org.opencv.core.Size; import org.opencv.imgproc.Imgproc; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.content.ContentResolver; import android.content.ContentValues; import android.content.DialogInterface; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.graphics.BitmapRegionDecoder; import android.graphics.Rect; import android.media.MediaScannerConnection; import android.media.MediaScannerConnection.OnScanCompletedListener; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.provider.MediaStore; import android.provider.MediaStore.Images; import android.support.v4.app.FragmentManager; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.Toast; import com.actionbarsherlock.app.ActionBar; import com.actionbarsherlock.app.SherlockDialogFragment; import com.actionbarsherlock.app.SherlockFragment; import com.actionbarsherlock.app.SherlockFragmentActivity; import com.actionbarsherlock.view.Menu; import com.actionbarsherlock.view.MenuInflater; import com.actionbarsherlock.view.MenuItem; import com.actionbarsherlock.view.SubMenu; import com.nekomeshi312.uitools.NumberPicker2; public class WhiteBoardCheckFragment extends SherlockFragment { public interface WhiteBoardCheckCallback { public void onWhiteBoardCheckOK(String warpName); } private static final String TAG_FRAGMENT = "tag"; private static final String TAG_FILE_PATH = "filepath"; private static final String TAG_FILE_NAME = "filename"; private static final String TAG_WIDTH = "width"; private static final String TAG_HEIGHT = "height"; private static final String TAG_PREV_WIDTH = "prevWidth"; private static final String TAG_PREV_HEIGHT = "prevHeight"; private static final String TAG_IS_CAPTURED = "isCaptured"; private static final String TAG_WB_POS = "whiteboardPos"; private static final String LOG_TAG = "WhiteBoardCheckFragment"; private Activity mParentActivity = null; private int mPicWidth = -1; private int mPicHeight = -1; private int mPrevWidth = -1; private int mPrevHeight = -1; private String mFilePath = null; private String mFileName = null; private boolean mIsCaptured = true; private double[] mPreviewPoints = null; private boolean mArgsOK = true; private boolean mIsPictureOK = false;//Whiteboard???????true private ImageView mCapturedImageView = null; private WhiteBoardAreaView mWBCorrectionView = null; private FrameLayout mWBCheckViewBase = null; private Bitmap mPicBitmap = null; private boolean mIsFirstOnGlobalLayout = true; private Menu mMenu = null; private int mOutputWidth = 640; private int mOutputAspectWidth = 4; private int mOutputAspectHeight = 2; private String mMyTag = null; public static WhiteBoardCheckFragment newInstance(String tag, WhiteBoardCheckInfo checkInfo) { WhiteBoardCheckFragment frag = new WhiteBoardCheckFragment(); Bundle args = new Bundle(); args.putString(TAG_FRAGMENT, tag); args.putString(TAG_FILE_PATH, checkInfo.mFilePath); args.putString(TAG_FILE_NAME, checkInfo.mFileName); args.putInt(TAG_WIDTH, checkInfo.mPicWidth); args.putInt(TAG_HEIGHT, checkInfo.mPicHeight); args.putInt(TAG_PREV_WIDTH, checkInfo.mPrevWidth); args.putInt(TAG_PREV_HEIGHT, checkInfo.mPrevHeight); args.putBoolean(TAG_IS_CAPTURED, checkInfo.mIsCaptured); if (checkInfo.mDetectedPoints != null) { double[] points = new double[8]; for (int i = 0; i < 4; i++) { points[i * 2 + 0] = checkInfo.mDetectedPoints.get(i).x; points[i * 2 + 1] = checkInfo.mDetectedPoints.get(i).y; } args.putDoubleArray(TAG_WB_POS, points); } frag.setArguments(args); return frag; } /* (non-Javadoc) * @see com.actionbarsherlock.app.SherlockFragment#onAttach(android.app.Activity) */ @Override public void onAttach(Activity activity) { // TODO Auto-generated method stub super.onAttach(activity); if (!(activity instanceof WhiteBoardCheckCallback)) { Log.e(LOG_TAG, "Parent is not instance of WhiteBoardCheckCallback"); mParentActivity = null; return; } mParentActivity = activity; } /* (non-Javadoc) * @see com.actionbarsherlock.app.SherlockFragment#onDetach() */ @Override public void onDetach() { // TODO Auto-generated method stub super.onDetach(); if (mPicBitmap != null) { mPicBitmap.recycle(); } mParentActivity = null; if (MyDebug.DEBUG) Log.i(LOG_TAG, "onDetach"); } /* (non-Javadoc) * @see android.support.v4.app.Fragment#onCreate(android.os.Bundle) */ @Override public void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setHasOptionsMenu(true); mOutputWidth = CameraSettingActivity.getResolutionWidth(mParentActivity); mOutputAspectWidth = CameraSettingActivity.getAspectWidth(mParentActivity); mOutputAspectHeight = CameraSettingActivity.getAspectHeight(mParentActivity); } /* (non-Javadoc) * @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle) */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // TODO Auto-generated method stub if (MyDebug.DEBUG) Log.i(LOG_TAG, "onCreateView"); ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_white_board_check, container, false); final Bundle args = getArguments(); mArgsOK = true; if (args == null) { mArgsOK = false; } else { mMyTag = args.getString(TAG_FRAGMENT); mFilePath = args.getString(TAG_FILE_PATH); mFileName = args.getString(TAG_FILE_NAME); mPicWidth = args.getInt(TAG_WIDTH, -1); mPicHeight = args.getInt(TAG_HEIGHT, -1); mPrevWidth = args.getInt(TAG_PREV_WIDTH, -1); mPrevHeight = args.getInt(TAG_PREV_HEIGHT, -1); mPreviewPoints = args.getDoubleArray(TAG_WB_POS); mIsCaptured = args.getBoolean(TAG_IS_CAPTURED, true); if (mFilePath == null) { Log.w(LOG_TAG, "Invalid picture path"); mArgsOK = false; } if (mFileName == null) { Log.w(LOG_TAG, "Invalid picture name"); mArgsOK = false; } if (mPicWidth < 0) { Log.w(LOG_TAG, "Invalid picture width(" + mPicWidth + ")"); mArgsOK = false; } if (mPicHeight < 0) { Log.w(LOG_TAG, "Invalid picture height(" + mPicHeight + ")"); mArgsOK = false; } if (mPrevWidth < 0) { Log.w(LOG_TAG, "Invalid preview width(" + mPrevWidth + ")"); mArgsOK = false; } if (mPrevHeight < 0) { Log.w(LOG_TAG, "Invalid preview height(" + mPrevHeight + ")"); mArgsOK = false; } if (MyDebug.DEBUG) { Log.d(LOG_TAG, "FilePath = " + mFilePath); Log.d(LOG_TAG, "FileName = " + mFileName); Log.d(LOG_TAG, "PicWidth = " + mPicWidth); Log.d(LOG_TAG, "PicHeight = " + mPicHeight); Log.d(LOG_TAG, "PreviewWidth = " + mPrevWidth); Log.d(LOG_TAG, "PreviewHeight = " + mPrevHeight); if (mPreviewPoints == null) { Log.d(LOG_TAG, "mPreviewPoints = null"); } else { for (int i = 0; i < 4; i++) { Log.d(LOG_TAG, "PrevPoints(" + i + ") = " + mPreviewPoints[i * 2] + ":" + mPreviewPoints[i * 2 + 1]); } } } } ActionBar actionBar = ((SherlockFragmentActivity) mParentActivity).getSupportActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); mCapturedImageView = (ImageView) root.findViewById(R.id.captured_image); mWBCorrectionView = (WhiteBoardAreaView) root.findViewById(R.id.whiteboard_area_correction_view); mWBCorrectionView.setDraggable(true); mWBCheckViewBase = (FrameLayout) root.findViewById(R.id.area_check_view_base); mWBCheckViewBase.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() {//?view????????? // TODO Auto-generated method stub if (mIsFirstOnGlobalLayout) { //jpeg?WB??? mIsFirstOnGlobalLayout = false; LoadJpegFileAsyncTask loadJpegTask = new LoadJpegFileAsyncTask(); loadJpegTask.execute(); } } }); return root; } /* (non-Javadoc) * @see android.support.v4.app.Fragment#onDestroyView() */ @Override public void onDestroyView() { // TODO Auto-generated method stub super.onDestroyView(); } /* (non-Javadoc) * @see android.support.v4.app.Fragment#onResume() */ @Override public void onResume() { // TODO Auto-generated method stub super.onResume(); if (!mArgsOK) { Toast.makeText(mParentActivity, R.string.error_msg_saved_file_info, Toast.LENGTH_SHORT).show(); return; } } /* (non-Javadoc) * @see com.actionbarsherlock.app.SherlockFragment#onCreateOptionsMenu(com.actionbarsherlock.view.Menu, com.actionbarsherlock.view.MenuInflater) */ @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { // TODO Auto-generated method stub inflater.inflate(R.menu.fragment_whiteboard_check, menu); super.onCreateOptionsMenu(menu, inflater); } /* (non-Javadoc) * @see com.actionbarsherlock.app.SherlockFragment#onPrepareOptionsMenu(com.actionbarsherlock.view.Menu) */ @Override public void onPrepareOptionsMenu(Menu menu) { // TODO Auto-generated method stub mMenu = menu; setResolutionToOptionMenu(); setAspectToOptionMenu(); setCalcableToOptionMenu(); super.onPrepareOptionsMenu(menu); } /* (non-Javadoc) * @see com.actionbarsherlock.app.SherlockFragment#onOptionsItemSelected(com.actionbarsherlock.view.MenuItem) */ @Override public boolean onOptionsItemSelected(MenuItem item) { // TODO Auto-generated method stub switch (item.getItemId()) { case R.id.menu_resolution_select: setResolutionToOptionMenu(); Toast.makeText(mParentActivity, R.string.menu_resolution_explanation, Toast.LENGTH_SHORT).show(); return true; case R.id.menu_whiteboard_correct_ok: WarpImageAsyncTask task = new WarpImageAsyncTask(); task.execute(); return true; case R.id.menu_resolution_1920: mOutputWidth = 1920; CameraSettingActivity.setResolutionWidth(mParentActivity, mOutputWidth); return true; case R.id.menu_resolution_1280: mOutputWidth = 1280; CameraSettingActivity.setResolutionWidth(mParentActivity, mOutputWidth); return true; case R.id.menu_resolution_1024: mOutputWidth = 1024; CameraSettingActivity.setResolutionWidth(mParentActivity, mOutputWidth); return true; case R.id.menu_resolution_640: mOutputWidth = 640; CameraSettingActivity.setResolutionWidth(mParentActivity, mOutputWidth); return true; case R.id.menu_aspect_select: setAspectToOptionMenu(); Toast.makeText(mParentActivity, R.string.menu_aspect_explanation, Toast.LENGTH_SHORT).show(); return true; case R.id.menu_aspect_4_3: setAspect(4, 3); return true; case R.id.menu_aspect_3_2: setAspect(3, 2); return true; case R.id.menu_aspect_16_10: setAspect(16, 10); return true; case R.id.menu_aspect_16_9: setAspect(16, 9); return true; case R.id.menu_aspect_2_1: setAspect(2, 1); return true; case R.id.menu_aspect_other: final ChoseAspectDlgFragment dlgFragment = ChoseAspectDlgFragment.newInstance(mMyTag, mOutputAspectWidth, mOutputAspectHeight); dlgFragment.show(getSherlockActivity().getSupportFragmentManager(), "dialog"); return true; default: break; } return super.onOptionsItemSelected(item); } /** * WB???????????? */ private void setCalcableToOptionMenu() { try {//menu????menu????????????try/catch???????? MenuItem item = mMenu.findItem(R.id.menu_whiteboard_correct_ok); item.setEnabled(mIsPictureOK); } catch (Exception e) { if (MyDebug.DEBUG) e.printStackTrace(); return; } } /** * aspect???????aspect?? */ private void setAspectToOptionMenu() { try {//menu????menu????????????try/catch???????? MenuItem item = mMenu.findItem(R.id.menu_aspect_select); SubMenu subMenu = item.getSubMenu(); String currentTitle = String.format(mParentActivity.getString(R.string.menu_aspect_title_format), mOutputAspectWidth, mOutputAspectHeight); for (int i = 0; i < subMenu.size(); i++) { MenuItem subItem = subMenu.getItem(i); if (currentTitle.equals(subItem.getTitle())) { subItem.setChecked(true); return; } } //????????????????? MenuItem subItem = subMenu.getItem(subMenu.size() - 1); String title = String.format(mParentActivity.getString(R.string.menu_aspect_other_format), mOutputAspectWidth, mOutputAspectHeight); subItem.setTitle(title); subItem.setChecked(true); return; } catch (Exception e) { if (MyDebug.DEBUG) e.printStackTrace(); } } /** * ??????????? */ private void setResolutionToOptionMenu() { try {//menu????menu????????????try/catch???????? MenuItem item = mMenu.findItem(R.id.menu_resolution_select); SubMenu subMenu = item.getSubMenu(); String currentTitle = String.format(mParentActivity.getString(R.string.menu_resolution_title_format), mOutputWidth); for (int i = 0; i < subMenu.size(); i++) { MenuItem subItem = subMenu.getItem(i); if (currentTitle.equals(subItem.getTitle())) { subItem.setChecked(true); break; } } } catch (Exception e) { if (MyDebug.DEBUG) e.printStackTrace(); return; } } /** * ???aspect??? * @param widthaspect? * @param heightaspect? */ private void setAspect(int width, int height) { mOutputAspectWidth = width; mOutputAspectHeight = height; CameraSettingActivity.setAspectWidth(mParentActivity, mOutputAspectWidth); CameraSettingActivity.setAspectHeight(mParentActivity, mOutputAspectHeight); } /** * ????aspect?????aspect???? * @author masaki * */ public static class ChoseAspectDlgFragment extends SherlockDialogFragment { private static final int MAX_ASPECT_VAL = 100; private static final String KEY_WIDTH = "width"; private static final String KEY_HEIGHT = "height"; private static final String KEY_TAG = "tag"; /** * fragment?? * @param tag ??fragment??fragment????????????? * @param widthdefault? * @param heightdefault?? * @return */ public static ChoseAspectDlgFragment newInstance(String tag, int width, int height) { ChoseAspectDlgFragment frag = new ChoseAspectDlgFragment(); Bundle args = new Bundle(); args.putString(KEY_TAG, tag); args.putInt(KEY_WIDTH, width); args.putInt(KEY_HEIGHT, height); frag.setArguments(args); return frag; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { int width = getArguments().getInt(KEY_WIDTH); int height = getArguments().getInt(KEY_HEIGHT); final String tag = getArguments().getString(KEY_TAG); LayoutInflater inflater = getActivity().getLayoutInflater(); View view = inflater.inflate(R.layout.fragment_aspect_input, null, false); final NumberPicker2 pickWidth = (NumberPicker2) view.findViewById(R.id.aspect_select_width); final NumberPicker2 pickHeight = (NumberPicker2) view.findViewById(R.id.aspect_select_height); if (width < 1) width = 1; if (width > MAX_ASPECT_VAL) width = MAX_ASPECT_VAL; if (height < 1) height = 1; if (height > MAX_ASPECT_VAL) height = MAX_ASPECT_VAL; pickWidth.setRange(1, MAX_ASPECT_VAL); pickWidth.setCurrent(width); pickHeight.setRange(1, MAX_ASPECT_VAL); pickHeight.setCurrent(height); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()).setIcon(R.drawable.ic_launcher) .setTitle(R.string.aspect_dlg_title) .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub final int w = pickWidth.getCurrent(); final int h = pickHeight.getCurrent(); //?static????activity?tag?fragment???fragment????????? SherlockFragmentActivity activity = (SherlockFragmentActivity) getSherlockActivity(); FragmentManager fm = activity.getSupportFragmentManager(); WhiteBoardCheckFragment parentFragment = (WhiteBoardCheckFragment) fm .findFragmentByTag(tag); parentFragment.setAspect(w, h); } }).setNegativeButton("Cancel", null); builder.setView(view); return builder.create(); } } /** * warp????? * @author masaki * */ public static class WarpResultDlgFragment extends SherlockDialogFragment { /* (non-Javadoc) * @see android.support.v4.app.Fragment#onResume() */ @Override public void onResume() { // TODO Auto-generated method stub super.onResume(); } private static final String KEY_TAG = "tag"; private static final String KEY_AFTER_FILENAME = "afterfn"; private static final String KEY_BEFORE_FILENAME = "beforefn"; private static final int IMG_SIZE = 200;//dip private String mBeforeFn = null; private String mAfterFn = null; private Bitmap mBeforeBM = null; private Bitmap mAfterBM = null; /** * fragment?? * @param tag?tag ??????? * @param beforeFnwarp?????? * @param afterFn warp????? * @return */ public static WarpResultDlgFragment newInstance(String tag, String beforeFn, String afterFn) { WarpResultDlgFragment frag = new WarpResultDlgFragment(); Bundle args = new Bundle(); args.putString(KEY_TAG, tag); args.putString(KEY_BEFORE_FILENAME, beforeFn); args.putString(KEY_AFTER_FILENAME, afterFn); frag.setArguments(args); return frag; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { mBeforeFn = getArguments().getString(KEY_BEFORE_FILENAME); mAfterFn = getArguments().getString(KEY_AFTER_FILENAME); final String tag = getArguments().getString(KEY_TAG); //????px->dip?? final float scale = getActivity().getResources().getDisplayMetrics().density; final int imgsize = (int) ((double) IMG_SIZE * scale + 0.5); LayoutInflater inflater = getActivity().getLayoutInflater(); View view = inflater.inflate(R.layout.fragment_warp_result, null, false); mBeforeBM = MyUtils.loadJpeg(mBeforeFn, imgsize, imgsize); mAfterBM = MyUtils.loadJpeg(mAfterFn, imgsize, imgsize); ImageView iv = (ImageView) view.findViewById(R.id.image_warp_before); iv.setImageBitmap(mBeforeBM); iv = (ImageView) view.findViewById(R.id.image_warp_after); iv.setImageBitmap(mAfterBM); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()).setIcon(R.drawable.ic_launcher) .setTitle(R.string.warp_check_dlg_title) .setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub //warp??? File f = new File(mBeforeFn); f.delete(); //???jpge?? String[] mimeTypes = { "image/jpeg" }; MediaScannerConnection.scanFile(getSherlockActivity(), new String[] { mAfterFn }, mimeTypes, new OnScanCompletedListener() { @Override public void onScanCompleted(String path, Uri uri) { // TODO Auto-generated method stub if (MyDebug.DEBUG) { Log.d("MediaScannerConnection", "Scanned " + path + ":"); Log.d("MediaScannerConnection", "-> uri=" + uri); } } }); //fragment??????????? SherlockFragmentActivity activity = (SherlockFragmentActivity) getSherlockActivity(); FragmentManager fm = activity.getSupportFragmentManager(); WhiteBoardCheckFragment parentFragment = (WhiteBoardCheckFragment) fm .findFragmentByTag(tag); WhiteBoardCheckCallback callback = (WhiteBoardCheckCallback) parentFragment.mParentActivity; callback.onWhiteBoardCheckOK(mAfterFn); } }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // TODO Auto-generated method stub deleteAllImgFile(); } }).setCancelable(false); builder.setView(view); Dialog dlg = builder.create(); return dlg; } /** * warp??warp??? */ private void deleteAllImgFile() { File f = new File(mBeforeFn); f.delete(); f = new File(mAfterFn); f.delete(); } /* (non-Javadoc) * @see android.support.v4.app.DialogFragment#onCancel(android.content.DialogInterface) */ @Override public void onCancel(DialogInterface dialog) { // TODO Auto-generated method stub super.onCancel(dialog); deleteAllImgFile(); } /* (non-Javadoc) * @see android.support.v4.app.DialogFragment#onDismiss(android.content.DialogInterface) */ @Override public void onDismiss(DialogInterface dialog) { // TODO Auto-generated method stub super.onDismiss(dialog); if (mBeforeBM != null) mBeforeBM.recycle(); if (mAfterBM != null) mAfterBM.recycle(); } } /** * warp??????AsyncTask * @author masaki * */ private class WarpImageAsyncTask extends AsyncTask<Void, Void, Integer> { private static final int RESULT_STATUS_OK = 0; private static final int RESULT_STATUS_FILE_LOAD_ERROR = 1; private static final int RESULT_STATUS_FILE_SAVE_ERROR = 2; private static final int RESULT_STATUS_OUT_OF_MEMORY = 3; private ProgressDialog mLoadingDialog; private Mat mWarpImg; private ArrayList<Point> mCornerPointUnwarp = new ArrayList<Point>(); private Size mTargetSize = new Size(); private String mClippedFileName = null; private String mWarpedFileName = null; private void deleteFiles() { if (mWarpedFileName != null) { File f = new File(mWarpedFileName); f.delete(); } if (mClippedFileName != null) { File f = new File(mClippedFileName); f.delete(); } } /* (non-Javadoc) * @see android.os.AsyncTask#onCancelled() */ @Override protected void onCancelled() { // TODO Auto-generated method stub super.onCancelled(); try { if (mLoadingDialog != null) mLoadingDialog.dismiss(); } catch (IllegalArgumentException e) {//?activity??????????? e.printStackTrace(); } mLoadingDialog = null; if (mWarpImg != null) { mWarpImg.release(); mWarpImg = null; } deleteFiles(); } /* (non-Javadoc) * @see android.os.AsyncTask#onPostExecute(java.lang.Object) */ @Override protected void onPostExecute(Integer result) { // TODO Auto-generated method stub super.onPostExecute(result); try { if (mLoadingDialog != null) mLoadingDialog.dismiss(); } catch (IllegalArgumentException e) {//?activity??????????? e.printStackTrace(); } mLoadingDialog = null; if (mWarpImg != null) { mWarpImg.release(); mWarpImg = null; } switch (result) { case RESULT_STATUS_FILE_LOAD_ERROR: Toast.makeText(mParentActivity, R.string.error_msg_cant_load_image_file, Toast.LENGTH_SHORT).show(); deleteFiles(); break; case RESULT_STATUS_FILE_SAVE_ERROR: Toast.makeText(mParentActivity, R.string.error_msg_cant_save_image_file, Toast.LENGTH_SHORT).show(); deleteFiles(); break; case RESULT_STATUS_OUT_OF_MEMORY: Toast.makeText(mParentActivity, R.string.error_msg_warp_out_of_memory, Toast.LENGTH_SHORT).show(); deleteFiles(); break; case RESULT_STATUS_OK://warp?warp?? final WarpResultDlgFragment dlgFragment = WarpResultDlgFragment.newInstance(mMyTag, mClippedFileName, mWarpedFileName); dlgFragment.show(getSherlockActivity().getSupportFragmentManager(), "dialog"); break; } } /* (non-Javadoc) * @see android.os.AsyncTask#onPreExecute() */ @Override protected void onPreExecute() { // TODO Auto-generated method stub super.onPreExecute(); mLoadingDialog = new ProgressDialog(mParentActivity); String msg = mParentActivity.getString(R.string.wait_a_minute); mLoadingDialog.setMessage(msg); // ???????? mLoadingDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); mLoadingDialog.setCancelable(false); // mLoadingDialog.show(); } /** * jpegWB?????????????????????????????WB????? * @return true:?false: * @throws OutOfMemoryError? */ private boolean loadJpegAndCalcTargetAreaSize() throws OutOfMemoryError { try { final ArrayList<Point> corners = mWBCorrectionView.getWhiteBoardCorners(); // int rectLeft = Integer.MAX_VALUE; int rectRight = Integer.MIN_VALUE; int rectTop = Integer.MAX_VALUE; int rectBottom = Integer.MIN_VALUE; for (Point p : corners) { if (p.x < rectLeft) rectLeft = (int) (p.x + 0.5); if (p.y < rectTop) rectTop = (int) (p.y + 0.5); if (p.x > rectRight) rectRight = (int) (p.x + 0.5); if (p.y > rectBottom) rectBottom = (int) (p.y + 0.5); } //????? final int imgWidth = mPicBitmap.getWidth(); final int imgHeight = mPicBitmap.getHeight(); if (MyDebug.DEBUG) Log.d(LOG_TAG, " imgsize = " + imgWidth + ":" + imgHeight + " rect = " + rectLeft + "/" + rectTop + "/" + rectRight + "/" + rectBottom); //??? BitmapFactory.Options opt = new BitmapFactory.Options(); opt.inJustDecodeBounds = true; final String fn = mFilePath + mFileName; BitmapFactory.decodeFile(fn, opt); double ratioW = (double) opt.outWidth / (double) imgWidth;//??????-> /??? double ratioH = (double) opt.outHeight / (double) imgHeight; if (MyDebug.DEBUG) Log.d(LOG_TAG, "ratio = " + ratioW + "/" + ratioH); //???????? Rect orgRct = new Rect(); orgRct.left = (int) (rectLeft * ratioW + 0.5); orgRct.right = (int) (rectRight * ratioW + 0.5); orgRct.top = (int) (rectTop * ratioH + 0.5); orgRct.bottom = (int) (rectBottom * ratioH + 0.5); if (orgRct.left < 0) orgRct.left = 0; if (orgRct.right >= opt.outWidth) orgRct.right = opt.outWidth - 1; if (orgRct.top < 0) orgRct.top = 0; if (orgRct.bottom >= opt.outHeight) orgRct.bottom = opt.outHeight - 1; //????aspect????? mTargetSize.width = mOutputWidth; mTargetSize.height = (int) ((double) mOutputWidth * (double) mOutputAspectHeight / (double) mOutputAspectWidth + 0.5); if (MyDebug.DEBUG) Log.d(LOG_TAG, "TargetSize = " + mTargetSize.width + "/" + mTargetSize.height); //????????? final int wStep = Math .max((int) ((double) (orgRct.right - orgRct.left) / (double) mTargetSize.width + 0.5), 1); final int hStep = Math .max((int) ((double) (orgRct.bottom - orgRct.top) / (double) mTargetSize.height + 0.5), 1); final int step = Math.min(wStep, hStep); //????? final int w = (int) ((double) (orgRct.right - orgRct.left) / (double) step + 0.5); final int h = (int) ((double) (orgRct.bottom - orgRct.top) / (double) step + 0.5); if (MyDebug.DEBUG) { Log.d(LOG_TAG, "Step = " + wStep + ":" + hStep + " Result Size = " + w + "/" + h); } //? opt.inSampleSize = step; //?? opt.inJustDecodeBounds = false; Bitmap bmp = null; BitmapRegionDecoder decoder; try { decoder = BitmapRegionDecoder.newInstance(fn, false); bmp = decoder.decodeRegion(orgRct, opt); //????????????? for (Point p : corners) { Point np = new Point(); np.x = (double) (p.x * ratioW - orgRct.left) / (double) step; np.y = (double) (p.y * ratioH - orgRct.top) / (double) step; mCornerPointUnwarp.add(np); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (bmp == null) return false; mWarpImg = new Mat(bmp.getWidth(), bmp.getHeight(), CvType.CV_8UC4); Utils.bitmapToMat(bmp, mWarpImg); bmp.recycle(); //????1/2^n??????????????????? Imgproc.resize(mWarpImg, mWarpImg, new Size(w, h)); if (MyDebug.DEBUG) { Log.d(LOG_TAG, "imgsize = " + mWarpImg.cols() + ":" + mWarpImg.rows()); final int sz = mCornerPointUnwarp.size(); for (int i = 0; i < sz; i++) { Core.line(mWarpImg, mCornerPointUnwarp.get(i), mCornerPointUnwarp.get((i + 1) % sz), new Scalar(0xff, 0x00, 0x00), 5); Log.d(LOG_TAG, "point = " + mCornerPointUnwarp.get(i).x + ":" + mCornerPointUnwarp.get(i).y); } } } catch (OutOfMemoryError e) { e.printStackTrace(); throw e; } return (true); } /** * bitmap??? * @param mBitmap ??bitmap * @param name ????? * @return???? */ private String saveBitmapToSd(Bitmap mBitmap, String name) { try { // ?? FileOutputStream fos = null; String fn = mFilePath + name; fos = new FileOutputStream(new File(fn)); // jpeg?? mBitmap.compress(CompressFormat.JPEG, 100, fos); // ?? fos.close(); return fn; } catch (Exception e) { Log.e("Error", "" + e.toString()); } return null; } @Override protected Integer doInBackground(Void... params) { // TODO Auto-generated method stub for (int i = 0; i < 2; i++) { try { if (loadJpegAndCalcTargetAreaSize() == false) return RESULT_STATUS_FILE_LOAD_ERROR; Bitmap bmp = Bitmap.createBitmap(mWarpImg.cols(), mWarpImg.rows(), Bitmap.Config.ARGB_8888); //warp???? Utils.matToBitmap(mWarpImg, bmp); String fn = saveBitmapToSd(bmp, "tmp.jpg"); bmp.recycle(); if (fn == null) return RESULT_STATUS_FILE_SAVE_ERROR; mClippedFileName = fn; break; } catch (OutOfMemoryError e1) { if (i == 1) return RESULT_STATUS_OUT_OF_MEMORY; e1.printStackTrace(); System.gc(); //out of memory???GC???????? } } //warp?homography? //??? MatOfPoint2f source = new MatOfPoint2f(mCornerPointUnwarp.get(0), mCornerPointUnwarp.get(1), mCornerPointUnwarp.get(2), mCornerPointUnwarp.get(3)); //?? Point p0 = new Point(); p0.x = 0; p0.y = 0; Point p1 = new Point(); p1.x = mTargetSize.width; p1.y = 0; Point p2 = new Point(); p2.x = mTargetSize.width; p2.y = mTargetSize.height; Point p3 = new Point(); p3.x = 0; p3.y = mTargetSize.height; MatOfPoint2f target = new MatOfPoint2f(p0, p1, p2, p3); //homography? Mat m = Calib3d.findHomography(source, target); //warp Imgproc.warpPerspective(mWarpImg, mWarpImg, m, mTargetSize, Imgproc.INTER_CUBIC); m.release(); //warp???? Bitmap bmp = Bitmap.createBitmap(mWarpImg.cols(), mWarpImg.rows(), Bitmap.Config.ARGB_8888); Utils.matToBitmap(mWarpImg, bmp); //warp???? String warpName = mFileName.replaceAll(mParentActivity.getString(R.string.picture_base_name), mParentActivity.getString(R.string.picture_warped_name)); String fn = saveBitmapToSd(bmp, warpName); if (fn == null) return RESULT_STATUS_FILE_SAVE_ERROR; mWarpedFileName = fn; bmp.recycle(); return RESULT_STATUS_OK; } } private class LoadJpegFileAsyncTask extends AsyncTask<Void, Integer, ArrayList<Point>> { private static final int PROGRESS_ERROR_CANT_DETECT_WB = -2; private static final int PROGRESS_ERROR_CANT_READ_FILE = -1; private static final int PROGRESS_STEP_JPEGSIZE_DECIDED = 0; private static final int PROGRESS_STEP_LOAD_JPEG = 1; private static final int PROGRESS_STEP_DETECT_LINE = 2; private static final int PROGRESS_STEP_DETECT_WB = 3; private ProgressDialog mLoadingDialog; private int mScreenWidth; private int mScreenHeight; /* (non-Javadoc) * @see android.os.AsyncTask#onCancelled() */ @Override protected void onCancelled() { // TODO Auto-generated method stub super.onCancelled(); try { if (mLoadingDialog != null) mLoadingDialog.dismiss(); } catch (IllegalArgumentException e) {//?activity??????????? e.printStackTrace(); } mLoadingDialog = null; Toast.makeText(mParentActivity, R.string.white_board_check_canceled, Toast.LENGTH_SHORT).show(); } /* (non-Javadoc) * @see android.os.AsyncTask#onPostExecute(java.lang.Object) */ @Override protected void onPostExecute(ArrayList<Point> result) { // TODO Auto-generated method stub super.onPostExecute(result); try { if (mLoadingDialog != null) mLoadingDialog.dismiss(); } catch (IllegalArgumentException e) {//?activity??????????? e.printStackTrace(); } mLoadingDialog = null; if (result != null) { mWBCorrectionView.setWhiteBoardCorners(result); mIsPictureOK = true; } setCalcableToOptionMenu(); } /* (non-Javadoc) * @see android.os.AsyncTask#onPreExecute() */ @Override protected void onPreExecute() { // TODO Auto-generated method stub super.onPreExecute(); mLoadingDialog = new ProgressDialog(mParentActivity); String msg = mParentActivity.getString(R.string.wait_a_minute); mLoadingDialog.setMessage(msg); // ???????? mLoadingDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); mLoadingDialog.setCancelable(false); // mLoadingDialog.show(); final View viewBase = (View) mParentActivity.findViewById(R.id.camera_view_base); mScreenWidth = viewBase.getWidth(); mScreenHeight = viewBase.getHeight(); if (MyDebug.DEBUG) Log.d(LOG_TAG, "viewBaseSize = " + mScreenWidth + ":" + mScreenHeight); mIsPictureOK = false; } /* (non-Javadoc) * @see android.os.AsyncTask#onProgressUpdate(Progress[]) */ @Override protected void onProgressUpdate(Integer... values) { // TODO Auto-generated method stub super.onProgressUpdate(values); switch (values[0]) { case PROGRESS_ERROR_CANT_READ_FILE: Toast.makeText(mParentActivity, R.string.error_msg_cant_load_image_file, Toast.LENGTH_SHORT).show(); break; case PROGRESS_ERROR_CANT_DETECT_WB: Toast.makeText(mParentActivity, R.string.error_msg_cant_detect_wb, Toast.LENGTH_SHORT).show(); break; case PROGRESS_STEP_JPEGSIZE_DECIDED: //jpeg????????view??????? final int w = values[1]; final int h = values[2]; FrameLayout.LayoutParams prm = (FrameLayout.LayoutParams) mWBCheckViewBase.getLayoutParams(); prm.width = w; prm.height = h; prm.gravity = Gravity.CENTER; mWBCheckViewBase.setLayoutParams(prm); break; case PROGRESS_STEP_LOAD_JPEG: //ImageView? mCapturedImageView.setImageBitmap(mPicBitmap); break; case PROGRESS_STEP_DETECT_LINE: break; case PROGRESS_STEP_DETECT_WB: break; } } @Override protected ArrayList<Point> doInBackground(Void... arg0) { // TODO Auto-generated method stub //jpeg final String fn = mFilePath + mFileName; mPicBitmap = MyUtils.loadJpeg(fn, mScreenWidth, mScreenHeight); if (mPicBitmap == null) { publishProgress(PROGRESS_ERROR_CANT_READ_FILE); return null; } //???jpeg????????? int w = mPicBitmap.getWidth(); int h = mPicBitmap.getHeight(); Mat pic = new Mat(w, h, CvType.CV_8UC4); Utils.bitmapToMat(mPicBitmap, pic); final double aspectScreen = (double) mScreenWidth / (double) mScreenHeight; final double aspectPic = (double) w / (double) h; if (aspectPic >= aspectScreen) {//Pic????->??? final double resize = (double) mScreenWidth / (double) w; h = (int) ((double) h * resize + 0.5); w = mScreenWidth; } else { final double resize = (double) mScreenHeight / (double) h; w = (int) ((double) w * resize + 0.5); h = mScreenHeight; } //??4?????? w = ((w >> 2) + 1) << 2; h = ((h >> 2) + 1) << 2; publishProgress(PROGRESS_STEP_JPEGSIZE_DECIDED, w, h); if (MyDebug.DEBUG) Log.d(LOG_TAG, "screen size = " + w + ":" + h); // Imgproc.resize(pic, pic, new Size(w, h)); mPicBitmap.recycle(); mPicBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Utils.matToBitmap(pic, mPicBitmap); //jpeg publishProgress(PROGRESS_STEP_LOAD_JPEG); // DetectLines lineDetector = new DetectLines(w, h, 4); int lines[] = new int[DetectLines.MAX_LINE_NUM * 5];// x5? ??x, y???? int lineNum = lineDetector.lineDetect(pic, false, null, lines); lineDetector.cleanUp(); pic.release(); pic = null; // publishProgress(PROGRESS_STEP_DETECT_LINE); //WB boolean wbResult = true; ArrayList<Point> points = null; if (lineNum < 4) { wbResult = false; } else {//?????????WB WhiteBoardDetect wbDetect = new WhiteBoardDetect(w, h); points = new ArrayList<Point>(); wbResult = wbDetect.detectWhiteBoard(lines, lineNum, points, null); publishProgress(PROGRESS_STEP_DETECT_WB); } if (!wbResult) {//WB??????? points = new ArrayList<Point>(); if (mPreviewPoints == null) {//preview?WB???????????????????? Point p = new Point(); p.x = (double) w / 4.0; p.y = (double) h / 4.0; points.add(p); p = new Point(); p.x = (double) w * 3.0 / 4.0; p.y = (double) h / 4.0; points.add(p); p = new Point(); p.x = (double) w * 3.0 / 4.0; p.y = (double) h * 3.0 / 4.0; points.add(p); p = new Point(); p.x = (double) w / 4.0; p.y = (double) h * 3.0 / 4.0; points.add(p); publishProgress(PROGRESS_ERROR_CANT_DETECT_WB); } else {//Preview??WB?????? for (int i = 0; i < 4; i++) { Point p = new Point(); p.x = (double) mPreviewPoints[i * 2 + 0] * (double) w / (double) mPrevWidth; p.y = (double) mPreviewPoints[i * 2 + 1] * (double) h / (double) mPrevHeight; points.add(p); } } } if (MyDebug.DEBUG && points != null) { for (int i = 0; i < 4; i++) Log.d(LOG_TAG, "corners(" + i + ")" + points.get(i).x + ":" + points.get(i).y); } //WB????????????null? return points; } } }