/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2019, Google Inc. * * camera_device.h - libcamera Android Camera Device */ #ifndef __ANDROID_CAMERA_DEVICE_H__ #define __ANDROID_CAMERA_DEVICE_H__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "camera_capabilities.h" #include "camera_metadata.h" #include "camera_stream.h" #include "camera_worker.h" #include "jpeg/encoder.h" struct CameraConfigData; class CameraDevice : protected libcamera::Loggable { public: static std::unique_ptr create(unsigned int id, std::shared_ptr cam); ~CameraDevice(); int initialize(const CameraConfigData *cameraConfigData); int open(const hw_module_t *hardwareModule); void close(); void flush(); unsigned int id() const { return id_; } camera3_device_t *camera3Device() { return &camera3Device_; } const CameraCapabilities *capabilities() const { return &capabilities_; } const std::shared_ptr &camera() const { return camera_; } const std::string &maker() const { return maker_; } const std::string &model() const { return model_; } int facing() const { return facing_; } int orientation() const { return orientation_; } unsigned int maxJpegBufferSize() const; void setCallbacks(const camera3_callback_ops_t *callbacks); const camera_metadata_t *getStaticMetadata(); const camera_metadata_t *constructDefaultRequestSettings(int type); int configureStreams(camera3_stream_configuration_t *stream_list); int processCaptureRequest(camera3_capture_request_t *request); void requestComplete(libcamera::Request *request); protected: std::string logPrefix() const override; private: LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraDevice) CameraDevice(unsigned int id, std::shared_ptr camera); struct Camera3RequestDescriptor { enum class Status { Pending, Success, Error, }; Camera3RequestDescriptor() = default; ~Camera3RequestDescriptor() = default; Camera3RequestDescriptor(libcamera::Camera *camera, const camera3_capture_request_t *camera3Request); Camera3RequestDescriptor &operator=(Camera3RequestDescriptor &&) = default; bool isPending() const { return status_ == Status::Pending; } uint32_t frameNumber_ = 0; std::vector buffers_; std::vector> frameBuffers_; CameraMetadata settings_; std::unique_ptr request_; camera3_capture_result_t captureResult_ = {}; Status status_ = Status::Pending; }; enum class State { Stopped, Flushing, Running, }; void stop(); std::unique_ptr createFrameBuffer(const buffer_handle_t camera3buffer, libcamera::PixelFormat pixelFormat, const libcamera::Size &size); void abortRequest(Camera3RequestDescriptor *descriptor) const; bool isValidRequest(camera3_capture_request_t *request) const; void notifyShutter(uint32_t frameNumber, uint64_t timestamp); void notifyError(uint32_t frameNumber, camera3_stream_t *stream, camera3_error_msg_code code) const; int processControls(Camera3RequestDescriptor *descriptor); void sendCaptureResults(); std::unique_ptr getResultMetadata( const Camera3RequestDescriptor &descriptor) const; unsigned int id_; camera3_device_t camera3Device_; CameraWorker worker_; libcamera::Mutex stateMutex_; /* Protects access to the camera state. */ State state_; std::shared_ptr camera_; std::unique_ptr config_; CameraCapabilities capabilities_; std::map> requestTemplates_; const camera3_callback_ops_t *callbacks_; std::vector streams_; libcamera::Mutex descriptorsMutex_; /* Protects descriptors_. */ std::queue> descriptors_; std::string maker_; std::string model_; int facing_; int orientation_; CameraMetadata lastSettings_; }; #endif /* __ANDROID_CAMERA_DEVICE_H__ */ 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (C) 2019, Raspberry Pi Ltd
#
# ctt_tools.py - camera tuning tool miscellaneous

import time
import re
import binascii
import os
import cv2
import numpy as np
import imutils
import sys
import matplotlib.pyplot as plt
from sklearn import cluster as cluster
from sklearn.neighbors import NearestCentroid as get_centroids

"""
This file contains some useful tools, the details of which aren't important to
understanding of the code. They ar collated here to attempt to improve code
readability in the main files.
"""


"""
obtain config values, unless it doesnt exist, in which case pick default
Furthermore, it can check if the input is the correct type
"""
def get_config(dictt, key, default, ttype):
    try:
        val = dictt[key]
        if ttype == 'string':
            val = str(val)
        elif ttype == 'num':
            if 'int' not in str(type(val)):
                if 'float' not in str(type(val)):
                    raise ValueError
        elif ttype == 'dict':
            if not isinstance(val, dict):
                raise ValueError
        elif ttype == 'list':
            if not isinstance(val, list):
                raise ValueError
        elif ttype == 'bool':
            ttype = int(bool(ttype))
        else:
            val = dictt[key]
    except (KeyError, ValueError):
        val = default
    return val


"""
argument parser
"""
def parse_input():
    arguments = sys.argv[1:]
    if len(arguments) % 2 != 0:
        raise ArgError('\n\nERROR! Enter value for each arguent passed.')
    params = arguments[0::2]
    vals = arguments[1::2]
    args_dict = dict(zip(params, vals))
    json_output = get_config(args_dict, '-o', None, 'string')
    directory = get_config(args_dict, '-i', None, 'string')
    config = get_config(args_dict, '-c', None, 'string')
    log_path = get_config(args_dict, '-l', None, 'string')
    if directory is None:
        raise ArgError('\n\nERROR! No input directory given.')
    if json_output is None:
        raise ArgError('\n\nERROR! No output json given.')
    return json_output, directory, config, log_path


"""
custom arg and macbeth error class
"""
class ArgError(Exception):
    pass
class MacbethError(Exception):
    pass


"""
correlation function to quantify match
"""
def correlate(im1, im2):
    f1 = im1.flatten()
    f2 = im2.flatten()
    cor = np.corrcoef(f1, f2)
    return cor[0][1]


"""
get list of files from directory
"""
def get_photos(directory='photos'):
    filename_list = []
    for filename in os.listdir(directory):
        if 'jp' in filename or '.dng' in filename:
            filename_list.append(filename)
    return filename_list


"""
display image for debugging... read at your own risk...
"""
def represent(img, name='image'):
    # if type(img) == tuple or type(img) == list:
    #     for i in range(len(img)):
    #         name = 'image {}'.format(i)
    #         cv2.imshow(name, img[i])
    # else:
    #     cv2.imshow(name, img)
    # cv2.waitKey(0)
    # cv2.destroyAllWindows()
    # return 0
    """
    code above displays using opencv, but this doesn't catch users pressing 'x'
    with their mouse to close the window....  therefore matplotlib is used....
    (thanks a lot opencv)
    """
    grid = plt.GridSpec(22, 1)
    plt.subplot(grid[:19, 0])
    plt.imshow(img, cmap='gray')
    plt.axis('off')
    plt.subplot(grid[21, 0])
    plt.title('press \'q\' to continue')
    plt.axis('off')
    plt.show()

    # f = plt.figure()
    # ax = f.add_subplot(211)
    # ax2 = f.add_subplot(122)
    # ax.imshow(img, cmap='gray')
    # ax.axis('off')
    # ax2.set_figheight(2)
    # ax2.title('press \'q\' to continue')
    # ax2.axis('off')
    # plt.show()


"""
reshape image to fixed width without distorting
returns image and scale factor
"""
def reshape(img, width):
    factor = width/img.shape[0]
    return cv2.resize(img, None, fx=factor, fy=factor), factor