android下根据公司需要修改后的能正常使用的坐标校准代码
来源:互联网 发布:柏林爱乐乐团知乎 编辑:程序博客网 时间:2024/05/10 12:47
用于电子书的屏(具体我也不是很清楚),故需要在android系统源代码中修改坐标校准算法。
上层代码应用在其它网页上也有,只是根据网上信息修改了校准算法(可上网查询,这里不再详述),同时将结果保存。代码如下:
package com.;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.Log;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;
public class Calibration extends Activity {
static final int SAMPLE_COUNTS = 5;
static final int POINT_DEGREE = 2;
static final int FACTOR_COUNTS = 7;
static final int TOP_LEFT = 0;
static final int TOP_RIGHT = 1;
static final int BOTTOM_RIGHT = 2;
static final int BOTTOM_LEFT = 3;
static final int CENTER = 4;
static final int X_AXIS = 0;
static final int Y_AXIS = 1;
static final int EDGE_GAP = 200;
static final String CALIBRATION_FILE = "/data/pointercal";
//static final String CALIBRATION_FILE = "/mnt/sdcard/pointercal";
static final String TAG = "Calibration";
static final boolean DEBUG = true;
private int X_RES;
private int Y_RES;
class calibration {
int x[] = new int[5];//TouchScreen的x坐标
int y[] = new int[5];//TouchScreen的y坐标
int xfb[] = new int[5];//LCD的x坐标
int yfb[] = new int[5];//LCD的y坐标
// float a[] = new float[2];
float a[] = new float[6];
};
private calibration cal;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Log.d(TAG, "onCreate");
cal = new calibration();
DisplayMetrics dpm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dpm);
X_RES = dpm.widthPixels;
Y_RES = dpm.heightPixels;
String str = String.format("X_RES = %d, Y_RES = %d", X_RES, Y_RES);
Log.d(TAG, str);
this.initScreenPoints();
setContentView(new MyView(this));
}
// TopLeft-->TopRight-->BottomRight-->BottomLeft-->Center
// 为240 * 320分辨率,我们使用50像素作为边缘的差距
private boolean initScreenPoints() {
String str;
cal.xfb[TOP_LEFT] = EDGE_GAP; // TopLeft
cal.yfb[TOP_LEFT] = EDGE_GAP;
str = String.format("cal.xfb[%d] = %d, cal.yfb[%d] = %d", TOP_LEFT, cal.xfb[TOP_LEFT], TOP_LEFT, cal.yfb[TOP_LEFT]);
Log.d("zxb", str);
cal.xfb[TOP_RIGHT] = X_RES - EDGE_GAP; // TopRight
cal.yfb[TOP_RIGHT] = EDGE_GAP;
str = String.format("cal.xfb[%d] = %d, cal.yfb[%d] = %d", TOP_RIGHT, cal.xfb[TOP_RIGHT], TOP_RIGHT, cal.yfb[TOP_RIGHT]);
Log.d("zxb", str);
cal.xfb[BOTTOM_RIGHT] = X_RES - EDGE_GAP; // BottomRight
cal.yfb[BOTTOM_RIGHT] = Y_RES - EDGE_GAP;
str = String.format("cal.xfb[%d] = %d, cal.yfb[%d] = %d", BOTTOM_RIGHT, cal.xfb[BOTTOM_RIGHT], BOTTOM_RIGHT, cal.yfb[BOTTOM_RIGHT]);
Log.d("zxb", str);
cal.xfb[BOTTOM_LEFT] = EDGE_GAP; // BottomLeft
cal.yfb[BOTTOM_LEFT] = Y_RES - EDGE_GAP;
str = String.format("cal.xfb[%d] = %d, cal.yfb[%d] = %d", BOTTOM_LEFT, cal.xfb[BOTTOM_LEFT], BOTTOM_LEFT, cal.yfb[BOTTOM_LEFT]);
Log.d("zxb", str);
cal.xfb[CENTER] = X_RES / 2; // Center
cal.yfb[CENTER] = Y_RES / 2;
str = String.format("cal.xfb[%d] = %d, cal.yfb[%d] = %d", CENTER, cal.xfb[CENTER], CENTER, cal.yfb[CENTER]);
Log.d("zxb", str);
return true;
}
private boolean perform_calibration() {
String str;
/*
cal.a[0] = ((float)(cal.x[1] - cal.x[0]) / (float)(cal.xfb[1] - cal.xfb[0]) + (float)(cal.x[2] - cal.x[3]) / (float)(cal.xfb[2] - cal.xfb[3])) / 2.0f;
cal.a[1] = ((float)(cal.y[3] - cal.y[0]) / (float)(cal.yfb[3] - cal.yfb[0]) + (float)(cal.y[2] - cal.y[1]) / (float)(cal.yfb[2] - cal.yfb[1])) / 2.0f;
str = String.format("cal.a[0] = %f, cal.a[1] = %f\n", cal.a[0], cal.a[1]);
Log.d(TAG, str);
return true;
*/
int j;
float n, xt, yt, xt2, yt2, xtyt, xl, xlxt, xlyt, yl, ylxt, ylyt;
float det, a, b, c, d, e, f;
float scaling = 65536.0f;
//Get sums for matrix
n = xt = yt = xt2 = yt2 = xtyt = xl = xlxt = xlyt = yl = ylxt = ylyt = a = b = c = d = e = f = 0.0f;
for(j=0; j<5; j++) {
n += 1.0;
xt += (float)cal.x[j];
yt += (float)cal.y[j];
xt2 += (float)(cal.x[j] * cal.x[j]);
yt2 += (float)(cal.y[j] * cal.y[j]);
xtyt += (float)(cal.x[j] * cal.y[j]);
xl += (float)(cal.xfb[j]);
xlxt += (float)(cal.xfb[j] * cal.x[j]);
xlyt += (float)(cal.xfb[j] * cal.y[j]);
yl += (float)cal.yfb[j];
ylxt += (float)(cal.yfb[j] * cal.x[j]);
ylyt += (float)(cal.yfb[j] * cal.y[j]);
}
// Get determinant of matrix -- check if determinant is too small
det = n * (xt2 * yt2 - xtyt * xtyt) + xt * (xtyt * yt - xt * yt2) + yt * (xt * xtyt - yt * xt2);
if(det < 0.1 && det > -0.1) {
str = String.format("ts_calibrate: determinant is too small -- %f\n", det);
Log.d(TAG, str);
return false;
}
a = n*(xlxt * yt2 - xtyt * xlyt) + xl * (xtyt * yt - xt * yt2) - yt * (xlxt * yt - xt * xlyt);
cal.a[0] = a / det;
b = n * (xt2 * xlyt - xtyt * xlxt) + xt * (xlxt * yt - xt * xlyt) - xl * (xt2 * yt - xt * xtyt);
cal.a[1] = b / det;
c = xl * (xt2 * yt2 - xtyt * xtyt) + xt * (xtyt * xlyt - xlxt * yt2) - yt * (xt2 * xlyt - xlxt * xtyt);
cal.a[2] = c / det;
d = n * (ylxt * yt2 - xtyt * ylyt) + yl * (xtyt * yt - xt * yt2) - yt * (ylxt * yt - xt * ylyt);
cal.a[3] = d / det;
e = n * (xt2 * ylyt - ylxt * xtyt) + xt * (ylxt * yt - xt * ylyt) - yl * (xt2 * yt - xt * xtyt);
cal.a[4] = e / det;
f = yl * (xt2 * yt2 - xtyt * xtyt) + xt * (xtyt * ylyt - ylxt * yt2) - yt * (xt2 * ylyt - ylxt * xtyt);
cal.a[5] = f / det;
str = String.format("cal.a[0] = %f cal.a[1] = %f cal.a[2] = %f cal.a[3] = %f cal.a[4] = %f cal.a[5] = %f\n",
cal.a[0], cal.a[1], cal.a[2], cal.a[3], cal.a[4], cal.a[5]);
Log.d(TAG, str);
return true;
}
private boolean saveCalibrationResult() {
FileOutputStream os;
String res = "";
try {
os = new FileOutputStream(CALIBRATION_FILE);
res = String.format("%f %f %f %f %f %f", cal.a[0], cal.a[1], cal.a[2], cal.a[3], cal.a[4], cal.a[5]);
Log.i(TAG, "calibration result=" + res);
os.write(res.getBytes());
os.close();
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
Log.w(TAG, "open calibration file write error: " + CALIBRATION_FILE);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
public class MyView extends View {
private Canvas cv;
private Paint paint;
private Bitmap bmp;
private int screen_pos;
private Context mContext;
public MyView(Context c) {
super(c);
// 镶满屏幕,没有标题
//Log.d(TAG, "MyView");
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
mContext = c;
paint = new Paint();
paint.setDither(true);
paint.setAntiAlias(true);
paint.setStrokeWidth(2);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
bmp = Bitmap.createBitmap(X_RES, Y_RES, Bitmap.Config.ARGB_8888);
cv = new Canvas(bmp);
screen_pos = 0;
drawCalibrationCross(screen_pos);
}
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(bmp, 0, 0, null);
}
private boolean drawCalibrationCross(int pos) {
if (DEBUG) {
Log.i("bigcren", "draw cross at pos " + pos);
}
cv.drawColor(Color.BLACK);
// 画的X线
cv.drawLine(cal.xfb[pos] - 30, cal.yfb[pos], cal.xfb[pos] - 3,
cal.yfb[pos], paint);
cv.drawLine(cal.xfb[pos] + 3, cal.yfb[pos], cal.xfb[pos] + 30,
cal.yfb[pos], paint);
// 画的Y线
cv.drawLine(cal.xfb[pos], cal.yfb[pos] - 30, cal.xfb[pos],
cal.yfb[pos] - 3, paint);
cv.drawLine(cal.xfb[pos], cal.yfb[pos] + 3, cal.xfb[pos],
cal.yfb[pos] + 30, paint);
invalidate();
return true;
}
public boolean onTouchEvent(MotionEvent event) {
float tmpx, tmpy;
boolean ret;
if (screen_pos > SAMPLE_COUNTS - 1) {
Log.i("bigcren", "get sample ok");
return true;
}
if (event.getAction() == MotionEvent.ACTION_UP) {
tmpx = event.getX();
tmpy = event.getY();
if (Math.abs(cal.xfb[screen_pos] - tmpx) > 15
&& Math.abs(cal.yfb[screen_pos] - tmpy) > 15) {
Toast.makeText(mContext, R.string.calibration_error,
Toast.LENGTH_SHORT).show();
return false;
}
cal.x[screen_pos] = (int) event.getX();//(int) (event.getX() * 4096.0 / (float) X_RES + 0.5);
cal.y[screen_pos] = (int) event.getY();//(int) (event.getY() * 4096.0 / (float) Y_RES + 0.5);
String str = String.format("cal.x[%d] = %d, cal.y[%d] = %d", screen_pos, cal.x[screen_pos], screen_pos, cal.y[screen_pos]);
Log.d(TAG, str);
/*
str = String.format("x[%d] = %d, y[%d] = %d", screen_pos, (int)event.getX(), screen_pos, (int)event.getY());
Log.d(TAG, str);
*/
if (screen_pos == 4) {
ret = perform_calibration();
if (ret) {
saveCalibrationResult();
finish();
return true;
} else {
screen_pos = 0;
Log.w(TAG, "Calibration failed");
}
} else {
Led.ControlLed(Integer.toString(screen_pos));
screen_pos++;
drawCalibrationCross(screen_pos);
}
}
return true;
}
}
}
将校准数据保存到文本文件后,就需要修改android系统源码中的InputDevice.java代码中。下面的代码有些加到MotionEvent generateAbsMotion(InputDevice device, long curTime, long curTimeNano, Display display, int orientation, int metaState)代码中for循环语句的最后面,其它加到该java文件的最后。因为手上暂时没有android的源代码,故无法解释generateAbsMotion函数中每条语句的意思。
//Begin-Modify by zxb for Calibration
x_tmp = reportData[j + MotionEvent.SAMPLE_X];
y_tmp = reportData[j + MotionEvent.SAMPLE_Y];
str = String.format("j = %d MotionEvent.SAMPLE_X = %d MotionEvent.SAMPLE_Y= %d", j, MotionEvent.SAMPLE_X, MotionEvent.SAMPLE_Y);
Log.i("zxb", str);
str = String.format(" 1 reportData[%d] = %f reportData[%d] = %f", j + MotionEvent.SAMPLE_X, reportData[j + MotionEvent.SAMPLE_X], j + MotionEvent.SAMPLE_Y, reportData[j + MotionEvent.SAMPLE_Y]);
Log.i("zxb", str);
if (device.tInfo != null) {
str = String.format("device.tInfo.x1 = %f device.tInfo.y1 = %f device.tInfo.z1 = %f", device.tInfo.x1, device.tInfo.y1, device.tInfo.z1);
Log.i("zxb", str);
reportData[j + MotionEvent.SAMPLE_X] = (device.tInfo.x1 * x_tmp + device.tInfo.y1 * y_tmp + device.tInfo.z1);// / device.tInfo.s;
str = String.format("device.tInfo.x2 = %f device.tInfo.y2 = %f device.tInfo.z2 = %f", device.tInfo.x2, device.tInfo.y2, device.tInfo.z2);
Log.i("zxb", str);
reportData[j + MotionEvent.SAMPLE_Y] = (device.tInfo.x2 * x_tmp + device.tInfo.y2 * y_tmp + device.tInfo.z2);// / device.tInfo.s;
}
str = String.format("2 reportData[%d] = %f reportData[%d] = %f", j + MotionEvent.SAMPLE_X, reportData[j + MotionEvent.SAMPLE_X], j + MotionEvent.SAMPLE_Y, reportData[j + MotionEvent.SAMPLE_Y]);
Log.i("zxb", str);
//End-Modify by zxb for Calibration
//Begin-Add by zxb for Calibration
static class TransformInfo {
static float x1;
static float y1;
static float z1;
static float x2;
static float y2;
static float z2;
TransformInfo() {
x1 = 1.0f;
y1 = 1.0f;
z1 = 0.0f;
x2 = 1.0f;
y2 = 1.0f;
z2 = 0.0f;
}
};
//End-Add by zxb for Calibration
//Begin-Add by zxb for Calibration
readCalibrationResult();
//End-Add by zxb for Calibration
//Begin-Add by zxb for Calibration
private void readCalibrationResult() {
try {
FileInputStream is = new FileInputStream(CALIBRATION_FILE);
Log.d("zxb", String.format("1 tInfo.x1 = %f tInfo.y1 = %f tInfo.z1 = %f tInfo.x2 = %f tInfo.y2 = %f tInfo.z2 = %f", tInfo.x1, tInfo.y1, tInfo.z1, tInfo.x2, tInfo.y2, tInfo.z2));
byte[] mBuffer = new byte[64];
int len = is.read(mBuffer);
is.close();
if (len > 0) {
int i;
for (i = 0; i < len; i++)
if (mBuffer[i] == '\n' || mBuffer[i] == 0)
break;
len = i;
}
if (len > 0) {
tInfo = new TransformInfo();
StringTokenizer st = new StringTokenizer(new String(mBuffer, 0, len));
tInfo.x1 = Float.parseFloat(st.nextToken());
tInfo.y1 = Float.parseFloat(st.nextToken());
tInfo.z1 = Float.parseFloat(st.nextToken());
tInfo.x2 = Float.parseFloat(st.nextToken());
tInfo.y2 = Float.parseFloat(st.nextToken());
tInfo.z2 = Float.parseFloat(st.nextToken());
Log.d("zxb", String.format("2 tInfo.x1 = %f tInfo.y1 = %f tInfo.z1 = %f tInfo.x2 = %f tInfo.y2 = %f tInfo.z2 = %f", tInfo.x1, tInfo.y1, tInfo.z1, tInfo.x2, tInfo.y2, tInfo.z2));
}
} catch (java.io.FileNotFoundException e) {
Log.i("InputDevice", "calibration file not found exception");
} catch (java.io.IOException e) {
Log.i("InputDevice", "io exception");
} catch (java.lang.NumberFormatException e) {
Log.i("InputDevice", "number format exception");
}
}
//End-Add by zxb for Calibration
};
根据输出坐标值与实际坐标值比较,此校准算法的优缺点是:在坐标不准确时能提高精度,但坐标比较准时会略降低精度;但提高的精度远大于降低的精度。
至于是使用android系统源码自带的校准算法还是采用本文的校准算法,就是仁者见仁智者见智了。因为我没有详细比较两者的优缺点。
- android下根据公司需要修改后的能正常使用的坐标校准代码
- 原先能正常使用的java,一段时间后无法使用
- 解决公司oracle数据库服务器,在不能上网的情况下数据库也能正常的在局域网中使用
- 有关wince下校准界面的修改
- eclipse maven 修改代码后都需要clean的解决办法
- android 修改kernel后,需要更新bionic下的kernel文件
- Android使用selector修改按钮正常和按下状态的颜色和形状
- 触摸屏的校准与坐标变换
- MyEclipse环境下,更改JDK后需要修改的配置。
- 加密后的php代码需要ZendGuardLoader模块才能正常运行
- Android Studio导入jar后无法识别、但项目能正常运行的问题
- http协议升级后代码需要做何修改才能正常运行
- 仿IOS时间选择,五级联动,可以根据自己爱好进行修改(公司需要这样的,效果好)
- iwms正常使用需要的权限
- WinCE下的触摸屏校准
- WinCE 下触摸屏的校准
- wince下的触摸校准
- 根据Excel单元格坐标修改单元格内的Value
- QTableWidget用法
- Android 自动开关机
- socket套接字使用的结构体
- clr via c#(框架设计)第3版读书笔记
- Sprint.Net+Nhibenate+Mvc学习
- android下根据公司需要修改后的能正常使用的坐标校准代码
- 关于jffs2文件系统如何掉电保护
- 应用软件系统架构设计的“七种武器”
- Net::Telnet使用小记
- 物联传感首创智能家居DIY
- CListCtrl中如何删除所有的列 - wrhwww - C++博客
- 搭建Dreamweaver CS5.5+PhoneGap移动开发环境
- JAVA如何把一个float四舍五入到小数点后2位,4位,或者其它指定位数.
- SQL Server 相关电子书