Script Color Cam

 avatar
unknown
python
9 months ago
17 kB
10
Indexable
# coding=utf-8
import mvsdk
import numpy as np
import cv2
import os
import time
import ctypes
import json

def main():
    # Перечисление доступных камер
    DevList = mvsdk.CameraEnumerateDevice()
    nDev = len(DevList)
    if nDev < 1:
        print("Камеры не обнаружены!")
        return
    
    # Вывод списка доступных камер
    for i, DevInfo in enumerate(DevList):
        print("{}: {} {}".format(i, DevInfo.GetFriendlyName(), DevInfo.GetPortType()))
    
    # Автоматический выбор камеры, если она только одна
    i = 0 if nDev == 1 else int(input("Выберите камеру: "))
    DevInfo = DevList[i]
    print(f"Выбрана камера: {DevInfo.GetFriendlyName()}")
    
    # Инициализация камеры
    hCamera = 0
    try:
        hCamera = mvsdk.CameraInit(DevInfo, -1, -1)
    except mvsdk.CameraException as e:
        print("Ошибка инициализации камеры ({}): {}".format(e.error_code, e.message))
        return
    
    # Получение параметров камеры
    cap = mvsdk.CameraGetCapability(hCamera)
    
    # Вывод информации о возможностях камеры
    print_capability(cap)
    
    # Буферы для хранения данных изображения
    pFrameBuffer = None
    pRawData = None
    
    try:
        # Сначала получим текущие параметры экспозиции
        ae_state = mvsdk.CameraGetAeState(hCamera)
        exposure_time = mvsdk.CameraGetExposureTime(hCamera)
        print(f"Текущее состояние автоэкспозиции: {'Включено' if ae_state else 'Выключено'}")
        print(f"Текущее время экспозиции: {exposure_time} мкс")
        
        # Выбор режима работы камеры
        # В нашем случае просто используем текущие настройки экспозиции
        
        # Отключение триггерного режима (непрерывная съемка)
        mvsdk.CameraSetTriggerMode(hCamera, 0)
        
        # Поиск 12-битного цветного формата среди доступных
        color12_format_index = None
        for i in range(cap.iMediaTypeDesc):
            desc = cap.pMediaTypeDesc[i]
            desc_text = desc.GetDescription()
            if "12" in desc_text and any(pattern in desc_text for pattern in ["Bayer", "RGB", "Color"]):
                color12_format_index = i
                print(f"Найден 12-битный цветной формат: {desc_text} (индекс {i})")
                break
        
        if color12_format_index is not None:
            # Установка найденного 12-битного формата
            mvsdk.CameraSetMediaType(hCamera, color12_format_index)
        else:
            print("12-битный цветной формат не найден, используется формат по умолчанию")
        
        # Проверка текущего формата
        current_media_type = mvsdk.CameraGetMediaType(hCamera)
        print(f"Текущий формат: {current_media_type}")
        
        # Получим текущий байеровский паттерн
        current_media_type_desc = cap.pMediaTypeDesc[current_media_type]
        bayer_type = current_media_type_desc.iMediaType
        bayer_pattern = determine_bayer_pattern(bayer_type)
        print(f"Паттерн Байера: {bayer_pattern}")
        
        # Установка формата вывода ISP для цветной камеры (RGB24)
        mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_RGB8)
        current_isp_format = mvsdk.CameraGetIspOutFormat(hCamera)
        print(f"Текущий формат ISP: 0x{current_isp_format:X}")
        
        # Запуск камеры
        mvsdk.CameraPlay(hCamera)
        
        # Расчет размера буфера (для RGB24)
        buffer_size = cap.sResolutionRange.iWidthMax * cap.sResolutionRange.iHeightMax * 3
        pFrameBuffer = mvsdk.CameraAlignMalloc(buffer_size, 16)
        
        # Захват кадра
        print("Ожидание кадра...")
        pRawData, FrameHead = mvsdk.CameraGetImageBuffer(hCamera, 3000)
        print(f"Получен кадр формата: 0x{FrameHead.uiMediaType:X}")
        
        # Вывод подробной информации о кадре
        print_frame_info(FrameHead)
        
        # Создадим папку для сохранения, если её нет
        output_dir = "./output"
        os.makedirs(output_dir, exist_ok=True)
        
        # Генерируем имя файла с временной меткой
        timestamp = time.strftime("%Y%m%d_%H%M%S")
        
        # Метаданные для правильной интерпретации файлов
        metadata = {
            'width': FrameHead.iWidth,
            'height': FrameHead.iHeight,
            'exposure_time_us': FrameHead.uiExpTime,
            'analog_gain': FrameHead.fAnalogGain,
            'r_gain': FrameHead.fRgain,
            'g_gain': FrameHead.fGgain,
            'b_gain': FrameHead.fBgain,
            'timestamp': timestamp,
            'bits': 12,
            'bytes_per_pixel': 1.5,  # 12-бит упакованный = 1.5 байта на пиксель
            'bayer_pattern': bayer_pattern,
            'format': f"0x{FrameHead.uiMediaType:X}"
        }
        
        # Сохранение метаданных
        metadata_path = os.path.join(output_dir, f"metadata_{timestamp}.json")
        with open(metadata_path, 'w') as f:
            json.dump(metadata, f, indent=4)
        print(f"Метаданные сохранены в {metadata_path}")
        
        # Сохранение исходного RAW изображения (12-битное цветное)
        raw_filename = f"raw12_{timestamp}.raw"
        raw_path = os.path.join(output_dir, raw_filename)
        raw_status = mvsdk.CameraSaveImage(hCamera, raw_path.encode('utf-8'),
                                         pRawData, FrameHead, mvsdk.FILE_RAW, 100)
        print(f"Сохранение 12-бит RAW: {'успешно' if raw_status == mvsdk.CAMERA_STATUS_SUCCESS else f'ошибка {raw_status}'}")
        
        # Обработка изображения через ISP (демозаикинг)
        isp_status = mvsdk.CameraImageProcess(hCamera, pRawData, pFrameBuffer, FrameHead)
        print(f"Обработка изображения ISP: {'успешно' if isp_status == mvsdk.CAMERA_STATUS_SUCCESS else f'ошибка {isp_status}'}")
        
        # Преобразование RGB буфера в изображение numpy
        frame_width = FrameHead.iWidth
        frame_height = FrameHead.iHeight
        
        # Создаем массив NumPy, указывающий на область памяти RGB данных
        buffer_ptr = ctypes.cast(pFrameBuffer, ctypes.POINTER(ctypes.c_ubyte))
        buffer_size = frame_width * frame_height * 3  # RGB = 3 байта на пиксель
        
        # Создаем np.ndarray, который ссылается на данные в buffer_ptr
        rgb_data = np.ctypeslib.as_array(buffer_ptr, shape=(buffer_size,))
        
        # Копируем данные для безопасности
        rgb_data = np.copy(rgb_data)
        
        # Преобразуем в 3D RGB массив
        rgb_image = rgb_data.reshape((frame_height, frame_width, 3))
        
        # Возможно потребуется изменить порядок каналов BGR -> RGB для OpenCV
        # rgb_image = cv2.cvtColor(rgb_image, cv2.COLOR_BGR2RGB)
        
        # Сохраняем обработанное RGB изображение в различных форматах
        
        # Сохранение в PNG (8-бит на канал)
        png_filename = f"rgb_{timestamp}.png"
        png_path = os.path.join(output_dir, png_filename)
        cv2.imwrite(png_path, rgb_image)
        print(f"Сохранение RGB PNG: файл {png_path} создан")
        
        # Сохранение в TIFF (16-бит на канал)
        # Масштабируем 8-бит (0-255) до 16-бит (0-65535)
        rgb_image_16bit = (rgb_image.astype(np.uint16) * 257)
        tiff_filename = f"rgb16_{timestamp}.tiff"
        tiff_path = os.path.join(output_dir, tiff_filename)
        cv2.imwrite(tiff_path, rgb_image_16bit)
        print(f"Сохранение RGB TIFF (16-бит): файл {tiff_path} создан")
        
        # Создаем текстовый файл с инструкцией по открытию в ImageJ
        instructions = """
Инструкция по открытию файлов в ImageJ:

1. Открытие 12-бит RAW файла:
   - File > Import > Raw...
   - Выберите файл raw12_*.raw
   - В диалоге укажите:
     - Width: {width}
     - Height: {height}
     - Offset to first image: 0
     - Number of images: 1
     - Gap between images: 0
     - Little-endian byte order: отметьте, если ваша система использует little-endian
     - Для неупакованного 12-бит: "16-bit Unsigned"
     - Для упакованного 12-бит необходимо использовать специальные плагины

2. Открытие 16-бит TIFF файла:
   - File > Open...
   - Выберите файл rgb16_*.tiff
   - Откроется автоматически как 16-бит RGB

3. Для цветного 12-бит RAW необходимо провести демозаикинг:
   - После открытия RAW используйте Plugins > Color > Demosaic...
   - Выберите соответствующий паттерн Байера: {bayer_pattern}

4. Для упакованных 12-бит RAW (если формат 12-bit Packed):
   - Рекомендуется использовать дополнительные утилиты от производителя камеры
   - Альтернатива: предварительная обработка в другой программе с последующим импортом как 16-бит TIFF

Параметры съемки:
- Время экспозиции: {exposure_time} мкс
- Аналоговое усиление: {analog_gain}
        """.format(
            width=FrameHead.iWidth,
            height=FrameHead.iHeight,
            bayer_pattern=bayer_pattern,
            exposure_time=FrameHead.uiExpTime,
            analog_gain=FrameHead.fAnalogGain
        )
        
        instructions_filename = f"imagej_instructions_{timestamp}.txt"
        instructions_path = os.path.join(output_dir, instructions_filename)
        with open(instructions_path, 'w') as f:
            f.write(instructions)
        print(f"Инструкции по открытию в ImageJ сохранены в {instructions_path}")
        
        # Выводим информацию о созданных файлах
        print("\nСозданные файлы:")
        created_files = [raw_filename, png_filename, tiff_filename, 
                        f"metadata_{timestamp}.json", f"imagej_instructions_{timestamp}.txt"]
        for filename in created_files:
            path = os.path.join(output_dir, filename)
            if os.path.exists(path):
                file_size = os.path.getsize(path)
                print(f"{path}: {file_size} байт")
        
        # Освобождение буфера изображения
        mvsdk.CameraReleaseImageBuffer(hCamera, pRawData)
        
    except mvsdk.CameraException as e:
        print(f"Ошибка камеры ({e.error_code}): {e.message}")
    except Exception as e:
        print(f"Общая ошибка: {e}")
        import traceback
        traceback.print_exc()
    finally:
        # Остановка и освобождение ресурсов
        if hCamera > 0:
            mvsdk.CameraStop(hCamera)
            mvsdk.CameraUnInit(hCamera)
        
        if pFrameBuffer is not None:
            try:
                mvsdk.CameraAlignFree(pFrameBuffer)
            except:
                pass
                
        print("Камера остановлена и ресурсы освобождены")

def determine_bayer_pattern(media_type):
    """Определяет паттерн Байера на основе кода формата медиа"""
    # Словарь соответствия кодов формата и паттернов Байера
    bayer_patterns = {
        # Коды из SDK
        mvsdk.CAMERA_MEDIA_TYPE_BAYGR8: "GRBG",
        mvsdk.CAMERA_MEDIA_TYPE_BAYRG8: "RGGB",
        mvsdk.CAMERA_MEDIA_TYPE_BAYGB8: "GBRG",
        mvsdk.CAMERA_MEDIA_TYPE_BAYBG8: "BGGR",
        mvsdk.CAMERA_MEDIA_TYPE_BAYGR10_MIPI: "GRBG",
        mvsdk.CAMERA_MEDIA_TYPE_BAYRG10_MIPI: "RGGB",
        mvsdk.CAMERA_MEDIA_TYPE_BAYGB10_MIPI: "GBRG",
        mvsdk.CAMERA_MEDIA_TYPE_BAYBG10_MIPI: "BGGR",
        mvsdk.CAMERA_MEDIA_TYPE_BAYGR10: "GRBG",
        mvsdk.CAMERA_MEDIA_TYPE_BAYRG10: "RGGB",
        mvsdk.CAMERA_MEDIA_TYPE_BAYGB10: "GBRG",
        mvsdk.CAMERA_MEDIA_TYPE_BAYBG10: "BGGR",
        mvsdk.CAMERA_MEDIA_TYPE_BAYGR12: "GRBG",
        mvsdk.CAMERA_MEDIA_TYPE_BAYRG12: "RGGB",
        mvsdk.CAMERA_MEDIA_TYPE_BAYGB12: "GBRG",
        mvsdk.CAMERA_MEDIA_TYPE_BAYBG12: "BGGR",
        mvsdk.CAMERA_MEDIA_TYPE_BAYGR12_PACKED: "GRBG",
        mvsdk.CAMERA_MEDIA_TYPE_BAYRG12_PACKED: "RGGB",
        mvsdk.CAMERA_MEDIA_TYPE_BAYGB12_PACKED: "GBRG",
        mvsdk.CAMERA_MEDIA_TYPE_BAYBG12_PACKED: "BGGR",
        mvsdk.CAMERA_MEDIA_TYPE_BAYGR16: "GRBG",
        mvsdk.CAMERA_MEDIA_TYPE_BAYRG16: "RGGB",
        mvsdk.CAMERA_MEDIA_TYPE_BAYGB16: "GBRG",
        mvsdk.CAMERA_MEDIA_TYPE_BAYBG16: "BGGR",
    }
    
    if media_type in bayer_patterns:
        return bayer_patterns[media_type]
    else:
        # Если не можем определить, возвращаем наиболее распространенный
        return "RGGB"

def print_frame_info(FrameHead):
    """Выводит подробную информацию о кадре"""
    print(f"Формат: 0x{FrameHead.uiMediaType:X}")
    print(f"Размер буфера: {FrameHead.uBytes} байт")
    print(f"Размеры: {FrameHead.iWidth}x{FrameHead.iHeight}")
    print(f"Время экспозиции: {FrameHead.uiExpTime} мкс")
    print(f"Аналоговое усиление: {FrameHead.fAnalogGain}")
    if FrameHead.fRgain > 0 or FrameHead.fGgain > 0 or FrameHead.fBgain > 0:
        print(f"RGB усиление: R={FrameHead.fRgain}, G={FrameHead.fGgain}, B={FrameHead.fBgain}")

def print_capability(cap):
    """Выводит информацию о возможностях камеры"""
    print("\n=== ВОЗМОЖНОСТИ КАМЕРЫ ===")
    
    # Проверка на монохромную камеру
    if cap.sIspCapacity.bMonoSensor:
        print("Тип камеры: Монохромная (черно-белая)")
    else:
        print("Тип камеры: Цветная")
    
    # Доступные форматы
    print("\nДоступные форматы данных:")
    for i in range(cap.iMediaTypeDesc):
        desc = cap.pMediaTypeDesc[i]
        media_type_code = desc.iMediaType
        print(f"  {i}: {desc.GetDescription()} (код: 0x{media_type_code:X})")
        if "Bayer" in desc.GetDescription() or "RGB" in desc.GetDescription():
            bayer_pattern = determine_bayer_pattern(media_type_code)
            print(f"     Паттерн Байера: {bayer_pattern}")
    
    # Доступные размеры
    print("\nДоступные размеры изображения:")
    for i in range(cap.iImageSizeDesc):
        desc = cap.pImageSizeDesc[i]
        print(f"  {i}: {desc.GetDescription()} - {desc.iWidth}x{desc.iHeight}")
    
    print("\nДиапазон возможных разрешений:")
    print(f"  Ширина: {cap.sResolutionRange.iWidthMin} - {cap.sResolutionRange.iWidthMax}")
    print(f"  Высота: {cap.sResolutionRange.iHeightMin} - {cap.sResolutionRange.iHeightMax}")
    
    # Режимы триггера
    print("\nДоступные режимы запуска:")
    for i in range(cap.iTriggerDesc):
        desc = cap.pTriggerDesc[i]
        print(f"  {i}: {desc.GetDescription()}")
    
    print("===========================\n")

if __name__ == "__main__":
    main()
Editor is loading...
Leave a Comment