/* * Copyright 2020 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. */ #include "CameraUtils.h" #include #include #include using namespace android::hardware::automotive::evs::V1_1; using ::android::sp; using ::std::string; using ::std::vector; using ::std::map; namespace android { namespace hardware { namespace automotive { namespace sv { namespace V1_0 { namespace implementation { bool isLogicalCamera(const camera_metadata_t* metadata) { if (metadata == nullptr) { // A logical camera device must have a valid camera metadata. return false; } // Looking for LOGICAL_MULTI_CAMERA capability from metadata. camera_metadata_ro_entry_t entry; int rc = find_camera_metadata_ro_entry(metadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry); if (0 != rc) { // No capabilities are found. return false; } for (size_t i = 0; i < entry.count; ++i) { uint8_t cap = entry.data.u8[i]; if (cap == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) { return true; } } return false; } vector getPhysicalCameraIds(sp camera) { if (camera == nullptr) { LOG(WARNING) << __FUNCTION__ << "The EVS camera object is invalid"; return {}; } CameraDesc desc; camera->getCameraInfo_1_1([&desc](const CameraDesc& info) { desc = info; }); vector physicalCameras; const camera_metadata_t* metadata = reinterpret_cast(&desc.metadata[0]); if (!isLogicalCamera(metadata)) { // EVS assumes that the device w/o a valid metadata is a physical // device. LOG(INFO) << desc.v1.cameraId << " is not a logical camera device."; physicalCameras.emplace_back(desc.v1.cameraId); return physicalCameras; } // Look for physical camera identifiers camera_metadata_ro_entry entry; int rc = find_camera_metadata_ro_entry(metadata, ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS, &entry); if (rc != 0) { LOG(ERROR) << "No physical camera ID is found for " << desc.v1.cameraId; return {}; } const uint8_t* ids = entry.data.u8; size_t start = 0; for (size_t i = 0; i < entry.count; ++i) { if (ids[i] == '\0') { if (start != i) { string id(reinterpret_cast(ids + start)); physicalCameras.emplace_back(id); } start = i + 1; } } LOG(INFO) << desc.v1.cameraId << " consists of " << physicalCameras.size() << " physical camera devices"; return physicalCameras; } string tagToString(uint32_t tag) { switch (tag) { case ANDROID_LENS_DISTORTION: return "ANDROID_LENS_DISTORTION"; case ANDROID_LENS_INTRINSIC_CALIBRATION: return "ANDROID_LENS_INTRINSIC_CALIBRATION"; case ANDROID_LENS_POSE_TRANSLATION: return "ANDROID_LENS_POSE_TRANSLATION"; case ANDROID_LENS_POSE_ROTATION: return "ANDROID_LENS_POSE_ROTATION"; default: LOG(WARNING) << "Cannot recognize the tag: " << tag; return {}; } } bool getParam(const camera_metadata_t* metadata, uint32_t tag, int size, float* param) { camera_metadata_ro_entry_t entry = camera_metadata_ro_entry_t(); int rc = find_camera_metadata_ro_entry(metadata, tag, &entry); if (rc != 0) { LOG(ERROR) << "No metadata found for " << tagToString(tag); return false; } if (entry.count != size || entry.type != TYPE_FLOAT) { LOG(ERROR) << "Unexpected size or type for " << tagToString(tag); return false; } const float* lensParam = entry.data.f; for (int i = 0; i < size; i++) { param[i] = lensParam[i]; } return true; } bool getAndroidCameraParams(sp camera, const string& cameraId, AndroidCameraParams& params) { if (camera == nullptr) { LOG(WARNING) << __FUNCTION__ << "The EVS camera object is invalid"; return {}; } CameraDesc desc = {}; camera->getPhysicalCameraInfo(cameraId, [&desc](const CameraDesc& info) { desc = info; }); if (desc.metadata.size() == 0) { LOG(ERROR) << "No metadata found for " << desc.v1.cameraId; return false; } const camera_metadata_t* metadata = reinterpret_cast(&desc.metadata[0]); // Look for ANDROID_LENS_DISTORTION if (!getParam(metadata, ANDROID_LENS_DISTORTION, kSizeLensDistortion, ¶ms.lensDistortion[0])) { return false; } // Look for ANDROID_LENS_INTRINSIC_CALIBRATION if (!getParam(metadata, ANDROID_LENS_INTRINSIC_CALIBRATION, kSizeLensIntrinsicCalibration, ¶ms.lensIntrinsicCalibration[0])) { return false; } // Look for ANDROID_LENS_POSE_TRANSLATION if (!getParam(metadata, ANDROID_LENS_POSE_TRANSLATION, kSizeLensPoseTranslation, ¶ms.lensPoseTranslation[0])) { return false; } // Look for ANDROID_LENS_POSE_ROTATION if (!getParam(metadata, ANDROID_LENS_POSE_ROTATION, kSizeLensPoseRotation, ¶ms.lensPoseRotation[0])) { return false; } return true; } vector convertToSurroundViewCameraParams( const map& androidCameraParamsMap) { vector result; // TODO(b/156101189): the cameras are in random order now. They need to be // sorted based on the camera position info from config file. for (const auto& entry : androidCameraParamsMap) { SurroundViewCameraParams svParams; // Android Camera format for intrinsics: [f_x, f_y, c_x, c_y, s] // // To corelib: // SurroundViewCameraParams.intrinsics = // [ f_x, s, c_x, // 0, f_y, c_y, // 0, 0, 1 ]; const float* intrinsics = &entry.second.lensIntrinsicCalibration[0]; svParams.intrinsics[0] = intrinsics[0]; svParams.intrinsics[1] = intrinsics[4]; svParams.intrinsics[2] = intrinsics[2]; svParams.intrinsics[3] = 0; svParams.intrinsics[4] = intrinsics[1]; svParams.intrinsics[5] = intrinsics[3]; svParams.intrinsics[6] = 0; svParams.intrinsics[7] = 0; svParams.intrinsics[8] = 1; // Android Camera format for lens distortion: // Radial: [kappa_1, kappa_2, kappa_3] // Tangential: [kappa_4, kappa_5] // // To corelib: // SurroundViewCameraParams.distortion = // [kappa_1, kappa_2, kappa_3, kappa_4]; const float* distortion = &entry.second.lensDistortion[0]; svParams.distorion[0] = distortion[0]; svParams.distorion[1] = distortion[1]; svParams.distorion[2] = distortion[2]; svParams.distorion[3] = distortion[3]; // Android Camera format for rotation: // quaternion coefficients (x,y,z,w) // // To corelib: // theta = 2 * acos(w) // a_x = x / sin(theta/2) // a_y = y / sin(theta/2) // a_z = z / sin(theta/2) // SurroundViewCameraParams.rvec = // [theta * a_x, theta * a_y, theta * a_z]; const float* rotation = &entry.second.lensPoseRotation[0]; const float theta = 2 * acos(rotation[3]); const float a_x = rotation[0] / sin(theta / 2); const float a_y = rotation[1] / sin(theta / 2); const float a_z = rotation[2] / sin(theta / 2); svParams.rvec[0] = theta * a_x; svParams.rvec[1] = theta * a_y; svParams.rvec[2] = theta * a_z; // Android Camera format for translation: Translation = (x,y,z) // // To corelib: // SurroundViewCameraParams.tvec = [x, y, z]; const float* translation = &entry.second.lensPoseTranslation[0]; svParams.tvec[0] = translation[0]; svParams.tvec[1] = translation[1]; svParams.tvec[2] = translation[2]; LOG(INFO) << "Camera parameters for " << entry.first << " have been converted to SV core lib format successfully"; result.emplace_back(svParams); } return result; } } // namespace implementation } // namespace V1_0 } // namespace sv } // namespace automotive } // namespace hardware } // namespace android