From 3c08f7a14d2233acd508421801ee3b56afead7d7 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 11 Apr 2012 12:39:58 +0000 Subject: [PATCH] Patch #1789 access to Android camera settings applied. --- .../camera_wrapper/camera_wrapper.cpp | 237 +++++++++++++++++- .../androidcamera/include/camera_properties.h | 59 ++++- .../include/opencv2/highgui/highgui_c.h | 49 ++++ modules/highgui/src/cap_android.cpp | 40 ++- 4 files changed, 377 insertions(+), 8 deletions(-) diff --git a/modules/androidcamera/camera_wrapper/camera_wrapper.cpp b/modules/androidcamera/camera_wrapper/camera_wrapper.cpp index 57b0db11d..d986a6177 100644 --- a/modules/androidcamera/camera_wrapper/camera_wrapper.cpp +++ b/modules/androidcamera/camera_wrapper/camera_wrapper.cpp @@ -86,6 +86,11 @@ protected: int emptyCameraCallbackReported; + static const char* flashModesNames[ANDROID_CAMERA_FLASH_MODES_NUM]; + static const char* focusModesNames[ANDROID_CAMERA_FOCUS_MODES_NUM]; + static const char* whiteBalanceModesNames[ANDROID_CAMERA_WHITE_BALANCE_MODES_NUM]; + static const char* antibandingModesNames[ANDROID_CAMERA_ANTIBANDING_MODES_NUM]; + void doCall(void* buffer, size_t bufferSize) { if (cameraCallback == 0) @@ -156,6 +161,68 @@ protected: camera->releaseRecordingFrame(dataPtr); } + // Split list of floats, returns number of floats found + static int split_float(const char *str, float* out, char delim, int max_elem_num, + char **endptr = NULL) + { + // Find the first float. + char *end = const_cast(str); + int elem_num = 0; + for(; elem_num < max_elem_num; elem_num++ ){ + char* curr_end; + out[elem_num] = (float)strtof(end, &curr_end); + // No other numbers found, finish the loop + if(end == curr_end){ + break; + } + if (*curr_end != delim) { + // When end of string, finish the loop + if (*curr_end == 0){ + elem_num++; + break; + } + else { + LOGE("Cannot find delimeter (%c) in str=%s", delim, str); + return -1; + } + } + // Skip the delimiter character + end = curr_end + 1; + } + if (endptr) + *endptr = end; + return elem_num; + } + + int is_supported(const char* supp_modes_key, const char* mode) + { + const char* supported_modes = params.get(supp_modes_key); + return strstr(supported_modes, mode) > 0; + } + + float getFocusDistance(int focus_distance_type){ + if (focus_distance_type >= 0 && focus_distance_type < 3) { + float focus_distances[3]; + const char* output = params.get(CameraParameters::KEY_FOCUS_DISTANCES); + int val_num = CameraHandler::split_float(output, focus_distances, ',', 3); + if(val_num == 3){ + return focus_distances[focus_distance_type]; + } else { + LOGE("Invalid focus distances."); + } + } + return -1; + } + + static int getModeNum(const char** modes, const int modes_num, const char* mode_name) + { + for (int i = 0; i < modes_num; i++){ + if(!strcmp(modes[i],mode_name)) + return i; + } + return -1; + } + public: CameraHandler(CameraCallback callback = 0, void* _userData = 0): cameraId(0), @@ -220,6 +287,42 @@ public: std::string cameraPropertyPreviewFormatString; }; +const char* CameraHandler::flashModesNames[ANDROID_CAMERA_FLASH_MODES_NUM] = +{ + CameraParameters::FLASH_MODE_AUTO, + CameraParameters::FLASH_MODE_OFF, + CameraParameters::FLASH_MODE_ON, + CameraParameters::FLASH_MODE_RED_EYE, + CameraParameters::FLASH_MODE_TORCH +}; + +const char* CameraHandler::focusModesNames[ANDROID_CAMERA_FOCUS_MODES_NUM] = +{ + CameraParameters::FOCUS_MODE_AUTO, + CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO, + CameraParameters::FOCUS_MODE_EDOF, + CameraParameters::FOCUS_MODE_FIXED, + CameraParameters::FOCUS_MODE_INFINITY +}; + +const char* CameraHandler::whiteBalanceModesNames[ANDROID_CAMERA_WHITE_BALANCE_MODES_NUM] = +{ + CameraParameters::WHITE_BALANCE_AUTO, + CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT, + CameraParameters::WHITE_BALANCE_DAYLIGHT, + CameraParameters::WHITE_BALANCE_FLUORESCENT, + CameraParameters::WHITE_BALANCE_INCANDESCENT, + CameraParameters::WHITE_BALANCE_SHADE, + CameraParameters::WHITE_BALANCE_TWILIGHT +}; + +const char* CameraHandler::antibandingModesNames[ANDROID_CAMERA_ANTIBANDING_MODES_NUM] = +{ + CameraParameters::ANTIBANDING_50HZ, + CameraParameters::ANTIBANDING_60HZ, + CameraParameters::ANTIBANDING_AUTO +}; + CameraHandler* CameraHandler::initCameraConnect(const CameraCallback& callback, int cameraId, void* userData, CameraParameters* prevCameraParameters) { @@ -229,7 +332,7 @@ CameraHandler* CameraHandler::initCameraConnect(const CameraCallback& callback, #ifdef ANDROID_r2_2_0 camera = Camera::connect(); -#else +#else /* This is 2.3 or higher. The connect method has cameraID parameter */ camera = Camera::connect(cameraId); #endif @@ -435,7 +538,6 @@ double CameraHandler::getProperty(int propIdx) u.str = cameraPropertySupportedPreviewSizesString.c_str(); return u.res; } - case ANDROID_CAMERA_PROPERTY_PREVIEW_FORMAT_STRING: { const char* fmt = params.get(CameraParameters::KEY_PREVIEW_FORMAT); @@ -456,7 +558,62 @@ double CameraHandler::getProperty(int propIdx) u.str = cameraPropertyPreviewFormatString.c_str(); return u.res; } - + case ANDROID_CAMERA_PROPERTY_EXPOSURE: + { + int exposure = params.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION); + return exposure; + } + case ANDROID_CAMERA_PROPERTY_FPS: + { + return params.getPreviewFrameRate(); + } + case ANDROID_CAMERA_PROPERTY_FLASH_MODE: + { + int flash_mode = getModeNum(CameraHandler::flashModesNames, + ANDROID_CAMERA_FLASH_MODES_NUM, + params.get(CameraParameters::KEY_FLASH_MODE)); + return flash_mode; + } + case ANDROID_CAMERA_PROPERTY_FOCUS_MODE: + { + int focus_mode = getModeNum(CameraHandler::focusModesNames, + ANDROID_CAMERA_FOCUS_MODES_NUM, + params.get(CameraParameters::KEY_FOCUS_MODE)); + return focus_mode; + } + case ANDROID_CAMERA_PROPERTY_WHITE_BALANCE: + { + int white_balance = getModeNum(CameraHandler::whiteBalanceModesNames, + ANDROID_CAMERA_WHITE_BALANCE_MODES_NUM, + params.get(CameraParameters::KEY_WHITE_BALANCE)); + return white_balance; + } + case ANDROID_CAMERA_PROPERTY_ANTIBANDING: + { + int antibanding = getModeNum(CameraHandler::antibandingModesNames, + ANDROID_CAMERA_ANTIBANDING_MODES_NUM, + params.get(CameraParameters::KEY_ANTIBANDING)); + return antibanding; + } + case ANDROID_CAMERA_PROPERTY_FOCAL_LENGTH: + { + float focal_length = params.getFloat(CameraParameters::KEY_FOCAL_LENGTH); + return focal_length; + } + case ANDROID_CAMERA_PROPERTY_FOCUS_DISTANCE_NEAR: + { + return getFocusDistance(ANDROID_CAMERA_FOCUS_DISTANCE_NEAR_INDEX); + } + case ANDROID_CAMERA_PROPERTY_FOCUS_DISTANCE_OPTIMAL: + { + return getFocusDistance(ANDROID_CAMERA_FOCUS_DISTANCE_OPTIMAL_INDEX); + } + case ANDROID_CAMERA_PROPERTY_FOCUS_DISTANCE_FAR: + { + return getFocusDistance(ANDROID_CAMERA_FOCUS_DISTANCE_FAR_INDEX); + } + default: + LOGW("CameraHandler::getProperty - Unsupported property."); }; return -1; } @@ -483,6 +640,80 @@ void CameraHandler::setProperty(int propIdx, double value) params.setPreviewSize(w, h); } break; + case ANDROID_CAMERA_PROPERTY_EXPOSURE: + { + int max_exposure = params.getInt("max-exposure-compensation"); + int min_exposure = params.getInt("min-exposure-compensation"); + if(max_exposure && min_exposure){ + int exposure = (int)value; + if(exposure >= min_exposure && exposure <= max_exposure){ + params.set("exposure-compensation", exposure); + } else { + LOGE("Exposure compensation not in valid range (%i,%i).", min_exposure, max_exposure); + } + } else { + LOGE("Exposure compensation adjust is not supported."); + } + } + break; + case ANDROID_CAMERA_PROPERTY_FLASH_MODE: + { + int new_val = (int)value; + if(new_val >= 0 && new_val < ANDROID_CAMERA_FLASH_MODES_NUM){ + const char* mode_name = flashModesNames[new_val]; + if(is_supported(CameraParameters::KEY_SUPPORTED_FLASH_MODES, mode_name)) + params.set(CameraParameters::KEY_FLASH_MODE, mode_name); + else + LOGE("Flash mode %s is not supported.", mode_name); + } else { + LOGE("Flash mode value not in valid range."); + } + } + break; + case ANDROID_CAMERA_PROPERTY_FOCUS_MODE: + { + int new_val = (int)value; + if(new_val >= 0 && new_val < ANDROID_CAMERA_FOCUS_MODES_NUM){ + const char* mode_name = focusModesNames[new_val]; + if(is_supported(CameraParameters::KEY_SUPPORTED_FOCUS_MODES, mode_name)) + params.set(CameraParameters::KEY_FOCUS_MODE, mode_name); + else + LOGE("Focus mode %s is not supported.", mode_name); + } else { + LOGE("Focus mode value not in valid range."); + } + } + break; + case ANDROID_CAMERA_PROPERTY_WHITE_BALANCE: + { + int new_val = (int)value; + if(new_val >= 0 && new_val < ANDROID_CAMERA_WHITE_BALANCE_MODES_NUM){ + const char* mode_name = whiteBalanceModesNames[new_val]; + if(is_supported(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE, mode_name)) + params.set(CameraParameters::KEY_WHITE_BALANCE, mode_name); + else + LOGE("White balance mode %s is not supported.", mode_name); + } else { + LOGE("White balance mode value not in valid range."); + } + } + break; + case ANDROID_CAMERA_PROPERTY_ANTIBANDING: + { + int new_val = (int)value; + if(new_val >= 0 && new_val < ANDROID_CAMERA_ANTIBANDING_MODES_NUM){ + const char* mode_name = antibandingModesNames[new_val]; + if(is_supported(CameraParameters::KEY_SUPPORTED_ANTIBANDING, mode_name)) + params.set(CameraParameters::KEY_ANTIBANDING, mode_name); + else + LOGE("Antibanding mode %s is not supported.", mode_name); + } else { + LOGE("Antibanding mode value not in valid range."); + } + } + break; + default: + LOGW("CameraHandler::setProperty - Unsupported property."); }; } diff --git a/modules/androidcamera/include/camera_properties.h b/modules/androidcamera/include/camera_properties.h index 56cbb7433..2fec745fa 100644 --- a/modules/androidcamera/include/camera_properties.h +++ b/modules/androidcamera/include/camera_properties.h @@ -5,7 +5,64 @@ enum { ANDROID_CAMERA_PROPERTY_FRAMEWIDTH = 0, ANDROID_CAMERA_PROPERTY_FRAMEHEIGHT = 1, ANDROID_CAMERA_PROPERTY_SUPPORTED_PREVIEW_SIZES_STRING = 2, - ANDROID_CAMERA_PROPERTY_PREVIEW_FORMAT_STRING = 3 + ANDROID_CAMERA_PROPERTY_PREVIEW_FORMAT_STRING = 3, + ANDROID_CAMERA_PROPERTY_FPS = 4, + ANDROID_CAMERA_PROPERTY_EXPOSURE = 5, + ANDROID_CAMERA_PROPERTY_FLASH_MODE = 101, + ANDROID_CAMERA_PROPERTY_FOCUS_MODE = 102, + ANDROID_CAMERA_PROPERTY_WHITE_BALANCE = 103, + ANDROID_CAMERA_PROPERTY_ANTIBANDING = 104, + ANDROID_CAMERA_PROPERTY_FOCAL_LENGTH = 105, + ANDROID_CAMERA_PROPERTY_FOCUS_DISTANCE_NEAR = 106, + ANDROID_CAMERA_PROPERTY_FOCUS_DISTANCE_OPTIMAL = 107, + ANDROID_CAMERA_PROPERTY_FOCUS_DISTANCE_FAR = 108 +}; + + +enum { + ANDROID_CAMERA_FLASH_MODE_AUTO = 0, + ANDROID_CAMERA_FLASH_MODE_OFF, + ANDROID_CAMERA_FLASH_MODE_ON, + ANDROID_CAMERA_FLASH_MODE_RED_EYE, + ANDROID_CAMERA_FLASH_MODE_TORCH, + ANDROID_CAMERA_FLASH_MODES_NUM +}; + +enum { + ANDROID_CAMERA_FOCUS_MODE_AUTO = 0, + ANDROID_CAMERA_FOCUS_MODE_CONTINUOUS_PICTURE, + ANDROID_CAMERA_FOCUS_MODE_CONTINUOUS_VIDEO, + ANDROID_CAMERA_FOCUS_MODE_EDOF, + ANDROID_CAMERA_FOCUS_MODE_FIXED, + ANDROID_CAMERA_FOCUS_MODE_INFINITY, + ANDROID_CAMERA_FOCUS_MODE_MACRO, + ANDROID_CAMERA_FOCUS_MODES_NUM +}; + +enum { + ANDROID_CAMERA_WHITE_BALANCE_AUTO = 0, + ANDROID_CAMERA_WHITE_BALANCE_CLOUDY_DAYLIGHT, + ANDROID_CAMERA_WHITE_BALANCE_DAYLIGHT, + ANDROID_CAMERA_WHITE_BALANCE_FLUORESCENT, + ANDROID_CAMERA_WHITE_BALANCE_INCANDESCENT, + ANDROID_CAMERA_WHITE_BALANCE_SHADE, + ANDROID_CAMERA_WHITE_BALANCE_TWILIGHT, + ANDROID_CAMERA_WHITE_BALANCE_WARM_FLUORESCENT, + ANDROID_CAMERA_WHITE_BALANCE_MODES_NUM +}; + +enum { + ANDROID_CAMERA_ANTIBANDING_50HZ = 0, + ANDROID_CAMERA_ANTIBANDING_60HZ, + ANDROID_CAMERA_ANTIBANDING_AUTO, + ANDROID_CAMERA_ANTIBANDING_OFF, + ANDROID_CAMERA_ANTIBANDING_MODES_NUM +}; + +enum { + ANDROID_CAMERA_FOCUS_DISTANCE_NEAR_INDEX = 0, + ANDROID_CAMERA_FOCUS_DISTANCE_OPTIMAL_INDEX, + ANDROID_CAMERA_FOCUS_DISTANCE_FAR_INDEX }; #endif // CAMERA_PROPERTIES_H diff --git a/modules/highgui/include/opencv2/highgui/highgui_c.h b/modules/highgui/include/opencv2/highgui/highgui_c.h index 6ba310371..2e619273e 100644 --- a/modules/highgui/include/opencv2/highgui/highgui_c.h +++ b/modules/highgui/include/opencv2/highgui/highgui_c.h @@ -436,6 +436,16 @@ enum CV_CAP_PROP_XI_AEAG_LEVEL = 419, // Average intensity of output signal AEAG should achieve(in %) CV_CAP_PROP_XI_TIMEOUT = 420, // Image capture timeout in milliseconds + // Properties for Android cameras + CV_CAP_PROP_ANDROID_FLASH_MODE = 8001, + CV_CAP_PROP_ANDROID_FOCUS_MODE = 8002, + CV_CAP_PROP_ANDROID_WHITE_BALANCE = 8003, + CV_CAP_PROP_ANDROID_ANTIBANDING = 8004, + CV_CAP_PROP_ANDROID_FOCAL_LENGTH = 8005, + CV_CAP_PROP_ANDROID_FOCUS_DISTANCE_NEAR = 8006, + CV_CAP_PROP_ANDROID_FOCUS_DISTANCE_OPTIMAL = 8007, + CV_CAP_PROP_ANDROID_FOCUS_DISTANCE_FAR = 8008, + // Properties of cameras available through AVFOUNDATION interface CV_CAP_PROP_IOS_DEVICE_FOCUS = 9001, CV_CAP_PROP_IOS_DEVICE_EXPOSURE = 9002, @@ -477,6 +487,45 @@ enum CV_CAP_ANDROID_COLOR_FRAME_RGBA = 4 }; +// supported Android camera flash modes +enum { + CV_CAP_ANDROID_FLASH_MODE_AUTO = 0, + CV_CAP_ANDROID_FLASH_MODE_OFF, + CV_CAP_ANDROID_FLASH_MODE_ON, + CV_CAP_ANDROID_FLASH_MODE_RED_EYE, + CV_CAP_ANDROID_FLASH_MODE_TORCH +}; + +// supported Android camera focus modes +enum { + CV_CAP_ANDROID_FOCUS_MODE_AUTO = 0, + CV_CAP_ANDROID_FOCUS_MODE_CONTINUOUS_VIDEO, + CV_CAP_ANDROID_FOCUS_MODE_EDOF, + CV_CAP_ANDROID_FOCUS_MODE_FIXED, + CV_CAP_ANDROID_FOCUS_MODE_INFINITY, + CV_CAP_ANDROID_FOCUS_MODE_MACRO +}; + +// supported Android camera white balance modes +enum { + CV_CAP_ANDROID_WHITE_BALANCE_AUTO = 0, + CV_CAP_ANDROID_WHITE_BALANCE_CLOUDY_DAYLIGHT, + CV_CAP_ANDROID_WHITE_BALANCE_DAYLIGHT, + CV_CAP_ANDROID_WHITE_BALANCE_FLUORESCENT, + CV_CAP_ANDROID_WHITE_BALANCE_INCANDESCENT, + CV_CAP_ANDROID_WHITE_BALANCE_SHADE, + CV_CAP_ANDROID_WHITE_BALANCE_TWILIGHT, + CV_CAP_ANDROID_WHITE_BALANCE_WARM_FLUORESCENT +}; + +// supported Android camera antibanding modes +enum { + CV_CAP_ANDROID_ANTIBANDING_50HZ = 0, + CV_CAP_ANDROID_ANTIBANDING_60HZ, + CV_CAP_ANDROID_ANTIBANDING_AUTO, + CV_CAP_ANDROID_ANTIBANDING_OFF +}; + /* retrieve or set capture properties */ CVAPI(double) cvGetCaptureProperty( CvCapture* capture, int property_id ); CVAPI(int) cvSetCaptureProperty( CvCapture* capture, int property_id, double value ); diff --git a/modules/highgui/src/cap_android.cpp b/modules/highgui/src/cap_android.cpp index 839694543..9e5788a8e 100644 --- a/modules/highgui/src/cap_android.cpp +++ b/modules/highgui/src/cap_android.cpp @@ -263,11 +263,30 @@ double CvCapture_Android::getProperty( int propIdx ) return (double)m_activity->getFrameWidth(); case CV_CAP_PROP_FRAME_HEIGHT: return (double)m_activity->getFrameHeight(); - case CV_CAP_PROP_SUPPORTED_PREVIEW_SIZES_STRING: - return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_SUPPORTED_PREVIEW_SIZES_STRING); + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_SUPPORTED_PREVIEW_SIZES_STRING); case CV_CAP_PROP_PREVIEW_FORMAT: return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_PREVIEW_FORMAT_STRING); + case CV_CAP_PROP_FPS: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_FPS); + case CV_CAP_PROP_EXPOSURE: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_EXPOSURE); + case CV_CAP_PROP_ANDROID_FLASH_MODE: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_FLASH_MODE); + case CV_CAP_PROP_ANDROID_FOCUS_MODE: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_FOCUS_MODE); + case CV_CAP_PROP_ANDROID_WHITE_BALANCE: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_WHITE_BALANCE); + case CV_CAP_PROP_ANDROID_ANTIBANDING: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_ANTIBANDING); + case CV_CAP_PROP_ANDROID_FOCAL_LENGTH: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_FOCAL_LENGTH); + case CV_CAP_PROP_ANDROID_FOCUS_DISTANCE_NEAR: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_FOCUS_DISTANCE_NEAR); + case CV_CAP_PROP_ANDROID_FOCUS_DISTANCE_OPTIMAL: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_FOCUS_DISTANCE_OPTIMAL); + case CV_CAP_PROP_ANDROID_FOCUS_DISTANCE_FAR: + return (double)m_activity->getProperty(ANDROID_CAMERA_PROPERTY_FOCUS_DISTANCE_FAR); default: CV_Error( CV_StsOutOfRange, "Failed attempt to GET unsupported camera property." ); break; @@ -288,11 +307,24 @@ bool CvCapture_Android::setProperty( int propIdx, double propValue ) case CV_CAP_PROP_FRAME_HEIGHT: m_activity->setProperty(ANDROID_CAMERA_PROPERTY_FRAMEHEIGHT, propValue); break; - case CV_CAP_PROP_AUTOGRAB: m_shouldAutoGrab=(propValue != 0); break; - + case CV_CAP_PROP_EXPOSURE: + m_activity->setProperty(ANDROID_CAMERA_PROPERTY_EXPOSURE, propValue); + break; + case CV_CAP_PROP_ANDROID_FLASH_MODE: + m_activity->setProperty(ANDROID_CAMERA_PROPERTY_FLASH_MODE, propValue); + break; + case CV_CAP_PROP_ANDROID_FOCUS_MODE: + m_activity->setProperty(ANDROID_CAMERA_PROPERTY_FOCUS_MODE, propValue); + break; + case CV_CAP_PROP_ANDROID_WHITE_BALANCE: + m_activity->setProperty(ANDROID_CAMERA_PROPERTY_WHITE_BALANCE, propValue); + break; + case CV_CAP_PROP_ANDROID_ANTIBANDING: + m_activity->setProperty(ANDROID_CAMERA_PROPERTY_ANTIBANDING, propValue); + break; default: CV_Error( CV_StsOutOfRange, "Failed attempt to SET unsupported camera property." ); return false;