Added the quality test for exposure compensation.
- Users have the choice of run all the tests or run tests for a range.
- The tests for a certain range will loop through all the values of
supported exposure compensation and draw the response curve.
Change-Id: Id330732fd5401bfe871b3c148c032c3247571cd9
diff --git a/apps/CtsVerifier/include/colorchecker/exposurecompensationtest.h b/apps/CtsVerifier/include/colorchecker/exposurecompensationtest.h
new file mode 100644
index 0000000..866b25e
--- /dev/null
+++ b/apps/CtsVerifier/include/colorchecker/exposurecompensationtest.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef EXPOSURECOMPENSATIONTEST_H
+#define EXPOSURECOMPENSATIONTEST_H
+
+#include <vector>
+
+#include "imagetesthandler.h"
+
+class ExposureCompensationTest : public ImageTestHandler {
+ public:
+ ExposureCompensationTest() : ImageTestHandler() {
+ initializeReferenceColors();
+ }
+ ExposureCompensationTest(int debugHeight, int debugWidth) :
+ ImageTestHandler(debugHeight, debugWidth) {
+ initializeReferenceColors();
+ }
+ ~ExposureCompensationTest() {}
+
+ void addDataToList(const float exposureValue,
+ const std::vector<Vec3f>* checkerColors) {
+ mExposureValues.push_back(exposureValue);
+ mCheckerColors.push_back(*checkerColors);
+ delete checkerColors;
+ }
+
+ void processData();
+
+ private:
+ void initializeReferenceColors();
+
+ std::vector<std::vector<Vec3f> > mCheckerColors;
+ std::vector<Vec3i> mReferenceColors;
+ std::vector<float> mExposureValues;
+};
+
+#endif
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/Android.mk b/apps/CtsVerifier/jni/cameraanalyzer/Android.mk
index 06e075e..cac9ab3 100644
--- a/apps/CtsVerifier/jni/cameraanalyzer/Android.mk
+++ b/apps/CtsVerifier/jni/cameraanalyzer/Android.mk
@@ -24,10 +24,10 @@
LOCAL_SRC_FILES := com_android_cts_verifier_camera_analyzer_CameraTests.cpp \
com_android_cts_verifier_camera_analyzer_ColorCheckerTest.cpp \
+ com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.cpp \
com_android_cts_verifier_camera_analyzer_AutoLockTest.cpp \
com_android_cts_verifier_camera_analyzer_MeteringTest.cpp \
- #com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.cpp \
- com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.cpp
+ #com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.cpp
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../include/colorchecker $(JNI_H_INCLUDE)
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.cpp b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.cpp
new file mode 100644
index 0000000..68c8256
--- /dev/null
+++ b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "ExposureCompensationJNI"
+#include <utils/Log.h>
+#include <vector>
+#include <string.h>
+
+#include "android/bitmap.h"
+#include "testingimage.h"
+#include "exposurecompensationtest.h"
+#include "vec2.h"
+
+#include "com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.h"
+
+jlong Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_createExposureCompensationTest(
+ JNIEnv* env,
+ jobject thiz,
+ jint debugHeight,
+ jint debugWidth) {
+
+ ExposureCompensationTest* testHandler =
+ new ExposureCompensationTest(debugHeight, debugWidth);
+ long handlerAddress = (long)testHandler;
+
+ return handlerAddress;
+}
+
+void Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_createExposureCompensationClass(
+ JNIEnv* env,
+ jobject thiz,
+ jlong inputImageAddress,
+ jlong inputHandlerAddress,
+ jlong checkerCenterAddress,
+ jlong checkerRadiusAddress,
+ jfloat exposureValue) {
+
+ ALOGV("JNI createExposureCompensationClass starts!");
+
+ long imageAddress = (long)inputImageAddress;
+ long handlerAddress = (long)inputHandlerAddress;
+
+ TestingImage *inputImage = (TestingImage*) imageAddress;
+ ExposureCompensationTest *testHandler =
+ (ExposureCompensationTest*) handlerAddress;
+
+ std::vector<std::vector< Vec2f > >* checkerCenter =
+ (std::vector<std::vector< Vec2f > >*) (long) checkerCenterAddress;
+ std::vector<std::vector< float > >* checkerRadius =
+ (std::vector<std::vector< float > >*) (long) checkerRadiusAddress;
+
+ const std::vector<Vec3f>* checkerValue =
+ inputImage->getColorChecker(3, 4, 0, 6,
+ checkerCenter, checkerRadius);
+ testHandler->addDataToList((float) exposureValue, checkerValue);
+ delete inputImage;
+}
+
+void Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_processExposureCompensationTest(
+ JNIEnv* env,
+ jobject thiz,
+ jlong inputHandlerAddress) {
+
+ long handlerAddress = (long) inputHandlerAddress;
+ ExposureCompensationTest *testHandler =
+ (ExposureCompensationTest*) handlerAddress;
+
+ testHandler->processData();
+}
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.h b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.h
new file mode 100644
index 0000000..c77f0e4
--- /dev/null
+++ b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef JNI_CAMERAANALYZER_EXPOSURECOMPENSATIONTEST_H
+#define JNI_CAMERAANALYZER_EXPOSURECOMPENSATIONTEST_H
+
+#include <jni.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+JNIEXPORT jlong JNICALL
+Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_createExposureCompensationTest(
+ JNIEnv* env,
+ jobject thiz,
+ jint debugHeight,
+ jint debugWidth);
+
+JNIEXPORT void JNICALL
+Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_createExposureCompensationClass(
+ JNIEnv* env,
+ jobject thiz,
+ jlong inputImageAddress,
+ jlong inputHandlerAddress,
+ jlong checkerCenterAddress,
+ jlong checkerRadiusAddress,
+ jfloat exposureValue);
+
+JNIEXPORT void JNICALL
+Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_processExposureCompensationTest(
+ JNIEnv* env,
+ jobject thiz,
+ jlong inputHandlerAddress);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/apps/CtsVerifier/lib/colorchecker/Android.mk b/apps/CtsVerifier/lib/colorchecker/Android.mk
index cdebfae..d76e639 100644
--- a/apps/CtsVerifier/lib/colorchecker/Android.mk
+++ b/apps/CtsVerifier/lib/colorchecker/Android.mk
@@ -29,10 +29,10 @@
vec2.cpp \
imagetesthandler.cpp \
colorcheckertest.cpp \
+ exposurecompensationtest.cpp \
autolocktest.cpp \
- meteringtest.cpp \
+ meteringtest.cpp
#whitebalancetest.cpp \
- exposurecompensationtest.cpp
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../include/colorchecker
LOCAL_SHARED_LIBRARIES := libstlport \
diff --git a/apps/CtsVerifier/lib/colorchecker/exposurecompensationtest.cpp b/apps/CtsVerifier/lib/colorchecker/exposurecompensationtest.cpp
new file mode 100644
index 0000000..3e58141
--- /dev/null
+++ b/apps/CtsVerifier/lib/colorchecker/exposurecompensationtest.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "ExposureCompensationTest"
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <cmath>
+#include <string>
+#include <stdio.h>
+
+#include "vec2.h"
+#include "vec3.h"
+#include "exposurecompensationtest.h"
+
+const float GAMMA_CORRECTION = 2.2f;
+void ExposureCompensationTest::processData() {
+ ALOGV("Start Processing Exposure Compensation Test Data!");
+ clearDebugImage();
+
+ int numTests = mExposureValues.size();
+ int numPatches = mCheckerColors[0].size();
+ ALOGV("Processing %d tests with %d patches", numTests, numPatches);
+
+ float minExposure = -3.0f;
+ float scale = 9.0f;
+ for (int i = 0; i < numTests; ++i) {
+ for (int j = 0; j < numPatches; ++j) {
+ int exposureRed = static_cast<int>((
+ log(static_cast<float>(mReferenceColors[j].r()))
+ / log(2.0f) * GAMMA_CORRECTION +
+ mExposureValues[i] - minExposure) * scale);
+ int exposureGreen = static_cast<int>((
+ log(static_cast<float>(mReferenceColors[j].g()))
+ / log(2.0f) * GAMMA_CORRECTION +
+ mExposureValues[i] - minExposure) * scale);
+ int exposureBlue = static_cast<int>((
+ log(static_cast<float>(mReferenceColors[j].b()))
+ / log(2.0f) * GAMMA_CORRECTION +
+ mExposureValues[i] - minExposure) * scale);
+
+ ALOGV("Match color at (%d, %d) is (%f, %f, %f)", i, j,
+ mCheckerColors[i][j].r(),
+ mCheckerColors[i][j].g(),
+ mCheckerColors[i][j].b());
+ ALOGV("Response curve red (%d, %f), blue (%d, %f), green (%d, %f)",
+ exposureRed, mCheckerColors[i][j].r(),
+ exposureGreen, mCheckerColors[i][j].g(),
+ exposureBlue, mCheckerColors[i][j].b());
+
+ Vec3i red(255, 0, 0);
+ Vec3i green(0, 255, 0);
+ Vec3i blue(0, 0, 255);
+
+ drawPoint(200 - exposureRed, mCheckerColors[i][j].r(), red);
+ drawPoint(200 - exposureGreen, mCheckerColors[i][j].g(), green);
+ drawPoint(200 - exposureBlue, mCheckerColors[i][j].b(), blue);
+ }
+ }
+ mExposureValues.clear();
+ mCheckerColors.clear();
+}
+
+void ExposureCompensationTest::initializeReferenceColors() {
+ mReferenceColors.resize(6);
+
+ mReferenceColors[0].set(243, 243, 242);
+ mReferenceColors[1].set(200, 200, 200);
+ mReferenceColors[2].set(160, 160, 160);
+ mReferenceColors[3].set(122, 122, 121);
+ mReferenceColors[4].set(85, 85, 85);
+ mReferenceColors[5].set(52, 52, 52);
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraAnalyzerActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraAnalyzerActivity.java
index aa12476..b4c7dbd 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraAnalyzerActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraAnalyzerActivity.java
@@ -209,7 +209,7 @@
ColorCheckerTest.getSingletonTest().updateCamera();
//WhiteBalanceTest.getSingletonTest().updateCamera();
- //ExposureCompensationTest.getSingletonTest().updateCamera();
+ ExposureCompensationTest.getSingletonTest().updateCamera();
MeteringTest.getSingletonTest().updateCamera();
AutoLockTest.getSingletonTest().updateCamera();
}
@@ -320,16 +320,16 @@
public void onClick(View v) {
Log.v(TAG, "Running new exposure compensation tests!");
- /*ExposureCompensationTest exposureCompensationTest =
+ ExposureCompensationTest exposureCompensationTest =
ExposureCompensationTest.getSingletonTest();
mCurrentTest = exposureCompensationTest;
- initializeAdapter();*/
+ initializeAdapter();
// Loads the memory address of the checker centers and radius
// from the this class and set the two values for the new test.
- //ExposureCompensationTest.setCheckerAddress(mCheckerCenterAddress,
- // mCheckerRadiusAddress);
+ ExposureCompensationTest.setCheckerAddress(mCheckerCenterAddress,
+ mCheckerRadiusAddress);
}
};
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ExposureCompensationTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ExposureCompensationTest.java
new file mode 100644
index 0000000..828840d
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ExposureCompensationTest.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.camera.analyzer;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.ImageFormat;
+import android.hardware.Camera;
+import android.util.Log;
+import android.widget.ImageView;
+
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Random;
+
+public class ExposureCompensationTest extends CameraTests {
+
+ private static final String TAG = "ExposureCompensationTest";
+
+ private float mExposureLevel;
+ private final Object mProcessingImage = new Object();
+ private final Object mAutoFocusing = new Object();
+ private long mTestHandler;
+ private String[] mTestResults;
+ private int mNumTests;
+ private Camera.Parameters mParams;
+
+ private static ExposureCompensationTest singletonTest = null;
+
+ private ExposureCompensationTest(){
+ super();
+ }
+
+ public void updateCamera() {
+ mParams = mTestCamera.getParameters();
+ Log.v(TAG, String.format("Exposure level is from %d to %d",
+ mParams.getMinExposureCompensation(),
+ mParams.getMaxExposureCompensation()));
+ mNumTests = (int) ((float) (mParams.getMaxExposureCompensation() -
+ mParams.getMinExposureCompensation())
+ * mParams.getExposureCompensationStep());
+ mTestResults = new String[mNumTests + 1];
+ for (int i = 0; i < mNumTests + 1; ++i) {
+ mTestResults[i] = "...";
+ }
+ }
+
+ public static synchronized ExposureCompensationTest getSingletonTest() {
+ if (singletonTest == null) {
+ Log.v(TAG, "Creating a new ExposureCompensationTest instance");
+ singletonTest = new ExposureCompensationTest();
+ singletonTest.initializeTest();
+ }
+ return singletonTest;
+ }
+
+ private void initializeTest() {
+ // Creates a native test handler with a 120x160 pixel debug output
+ mTestHandler = createExposureCompensationTest(200, 280);
+ }
+
+ @Override
+ public synchronized void run(int index){
+ Log.v(TAG, "ExposureCompensationTest thread started!");
+
+ int testRangeMin, testRangeMax;
+ if (index == 0) {
+ testRangeMin = mParams.getMinExposureCompensation();
+ testRangeMax = mParams.getMaxExposureCompensation();
+ } else {
+ testRangeMin = (int) ((float)(index - 1) / mParams.getExposureCompensationStep())
+ + mParams.getMinExposureCompensation();
+ testRangeMax = (int) ((float)(index) / mParams.getExposureCompensationStep())
+ + mParams.getMinExposureCompensation();
+ }
+
+ for (int i = testRangeMin;
+ i <= testRangeMax; i += 1){
+ mExposureLevel = i * mParams.getExposureCompensationStep();
+ Log.v(TAG, String.format("Current exposure level is %d", i));
+ int mCameraExposure;
+
+ do{
+ mParams.setExposureCompensation(i);
+ mTestCamera.setParameters(mParams);
+
+ try{
+ Log.v(TAG, "Waiting");
+ Thread.sleep(4000);
+ Log.v(TAG, "END Waiting");
+ } catch (InterruptedException e){
+ //TODO: error handling.
+ }
+
+ mParams = mTestCamera.getParameters();
+ mCameraExposure = mParams.getExposureCompensation();
+ Log.v(TAG, String.format("Camera exposure level is %d", mCameraExposure));
+ } while (mCameraExposure != i);
+
+ mTestCamera.takePicture(null, null, null, mTestJpegListener);
+
+ synchronized (mProcessingImage) {
+ try{
+ Log.v(TAG, "Start waiting for Image");
+ mProcessingImage.wait();
+ } catch (InterruptedException e){
+ Log.v(TAG, "Callback wait fails!");
+ }
+ }
+ }
+ processExposureCompensationTest(mTestHandler);
+ displayHandlerDebugOutput(mTestHandler);
+
+ Log.v(TAG, "Callback has returned!");
+ mParams.setExposureCompensation(0);
+ mTestCamera.setParameters(mParams);
+ }
+
+ private Camera.PictureCallback mTestJpegListener = new Camera.PictureCallback() {
+ public void onPictureTaken(byte[] data, Camera mCamera) {
+ Log.v(TAG, "Shutter pressed down!");
+ Log.v(TAG, String.format("Current exposure is %f", mExposureLevel));
+
+ try {
+ FileOutputStream outStream = new FileOutputStream(
+ String.format("/sdcard/exposure%d.jpg", System.currentTimeMillis()));
+ outStream.write(data);
+ outStream.close();
+ } catch (FileNotFoundException e) {
+ } catch (IOException e) {}
+
+ Bitmap inputImage;
+
+ inputImage = BitmapFactory.decodeByteArray(data, 0, data.length);
+ long bufferAddress = findNative(inputImage);
+ Log.v(TAG, "findNative method finishes");
+
+ inputImage.recycle();
+ data = null;
+ inputImage = null;
+ System.gc();
+
+ createExposureCompensationClass(bufferAddress, mTestHandler,
+ getCheckerCenter(), getCheckerRadius(),
+ mExposureLevel);
+ mCamera.startPreview();
+
+ synchronized (mProcessingImage) {
+ mProcessingImage.notifyAll();
+ }
+ }
+ };
+
+ @Override
+ public String getTestName(int index) {
+ switch (index) {
+ case 0:
+ return "EC All Range";
+ default:
+ return String.format("EC %d -> %d", (index - mNumTests / 2 - 1) * 10,
+ (index - mNumTests / 2) * 10);
+ }
+ }
+
+ @Override
+ public String getResult(int index) {
+ return mTestResults[index];
+ }
+
+ @Override
+ public int getNumTests() {
+ return mNumTests + 1;
+ }
+
+ @Override
+ public String getTestName() {
+ return "Exposure Compensation Test: \n";
+ }
+
+ private native long createExposureCompensationTest(int outputHeight, int outputWidth);
+
+ private native void createExposureCompensationClass(long bufferAddress, long handlerAddress,
+ long checkerCenterAddress, long checkerAadiusAddress, float mExposureLevel);
+
+ private native void processExposureCompensationTest(long handlerAddress);
+
+ static {
+ System.loadLibrary("cameraanalyzer");
+ }
+}