swat24

Передача изображения с камеры OV9655 на ПК

26 сообщений в этой теме

swat24    9

Добрый день.

Необходимо передать изображение из камеры OV9655 на ПК и отобразить его, Камера имеет выходной формат изображения RGB 565, с камеры считываю с использованием DCMI:

uint32_t cameraData = DCMI_ReadData();

И после этого передаю через USART на ПК:

USART_SendData(Open_USART, (uint8_t) cameraData>>24);
while (USART_GetFlagStatus(Open_USART, USART_FLAG_TC) == RESET)
{}

USART_SendData(Open_USART, (uint8_t) cameraData>>16);
while (USART_GetFlagStatus(Open_USART, USART_FLAG_TC) == RESET)
{}

USART_SendData(Open_USART, (uint8_t) cameraData>>8);
while (USART_GetFlagStatus(Open_USART, USART_FLAG_TC) == RESET)
{}

USART_SendData(Open_USART, (uint8_t) cameraData);
while (USART_GetFlagStatus(Open_USART, USART_FLAG_TC) == RESET)
{}

На компьютере принимаю через терминал и сохраняю в HEX файл. Скажите как потом его можно открыть? В качестве просмотрщика планирую использовать Java, но теперь вопрос как преобразовать данные с камеры в изображение.

Может уже кто-то имел опыт работы с данной камерой? Подскажите, как можно передать изображение с нее на ПК?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
andryxa    232

добавьте в начале файла шапку bmp формата и сохраните с расширением bmp и у вас получится готовая картинка которую сможете посмотреть чем угодно

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
swat24    9

ок, сейчас попробую, а передаю правильно? Начиная со старшего байта необходимо?

 

добавил шапку, но открывать не хочет как картинку, пишет файл поврежден

Изменено пользователем swat24

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
КЭС    1 199

Насколько я помню, в шапке должен быть указан размер файла и разрядность цветности. 

 

ПС. Попробуйте сначала "потренироваться на кошках", т.е. на заведомо известных данных простейших картинок. Я бы начал с одного пиксела :)

Изменено пользователем КЭС

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
swat24    9

Хорошо, а как-нибудь без шапки его можно открыть? каким-нибудь редактором? Я не особо уверен, что правильно передается с камеры изображение

Изменено пользователем swat24

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
andryxa    232

найдите в поиске картинку с таким-же разрешением и битностью как у вас и скопируйте от туда шапку. учтите что с камеры, если я не ошибаюсь данные начинают приходить начиная с верхнего левого угла и заканчивая правым нижним. В бмп файле они должны быть расположены наоборот, то есть задом на перед.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
swat24    9

не нахожу с 16 битным цветом изображения, попробовал создать в кореле и paint.net, но там или 24 бита, или 8 бит.

Ладно, попробую с камерой, которая уже JPEG выдает

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
andryxa    232

Я в фотошопе делал, только мне нужно было не для камеры, а для записи скриншота с дисплея на карту памяти. Какое у вас разрешение?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
mail_robot    1 444

по идее если в шапке указан верный размер файла и прочие служебные данные, то файл с абсолютно любыми данными (верными или нет) откроется без проблем. Разница будет только в том будет ли видно изображение или белый шум. Если не открывается, значит чтото с заголовком. Надо читать даташиты на bmp и вкуривать что именно не так

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
swat24    9
28 минут назад, andryxa сказал:

Какое у вас разрешение?

320x240, попробую еще с заголовком поиграться

http://www.fastgraph.com/help/bmp_header_format.html это правильный заголовок?

Изменено пользователем swat24

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
mail_robot    1 444
6 минут назад, swat24 сказал:

это правильный заголовок?

похож

теперь надо открыть картинку нормальную и сопоставить данные

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
swat24    9

Создал изображение в paint.net - изменил размер, вставил свое изображение, но все-равно пишет "формат данного файла не поддерживается"

 

Оставил заголовок не изменяя вообще и получается следующее, похоже и передача не правильная

Безымянный.bmp

Изменено пользователем swat24

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
andryxa    232

Держите правильную картинку (черная, вместо данных нули) 320х240 16 бит RGB. Свои данные можно подставить в любом хекс редакторе.

камера.bmp

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
swat24    9

Спасибо, в результате получается тоже, что и у меня с разноцветной мозайкой. Похоже не то считывается с камеры...

Смотрите, я считываю 32 бита данных с экрана, используются только 16 младших бит. И отправляю все, что принял. начиная со старшего байта. Правильно?

Изменено пользователем swat24

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
andryxa    232

Использовать нужно старшие 5 бит красного, синего и 6 бит зеленого, для RGB 565. Это у вас один пиксель 32 бита?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
swat24    9
9 минут назад, andryxa сказал:

Использовать нужно старшие 5 бит красного, синего и 6 бит зеленого, для RGB 565. Это у вас один пиксель 32 бита?

да, считывается с камеры по DCMI 32 бита

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
andryxa    232

Что-то вы путаете, глянул даташит на камеру http://electricstuff.co.uk/OV9655-datasheet-annotated.pdf выходной формат данных 8 бит 565. То есть вы должны читать побайтно, на каждый пиксел идет два байта, в которых 5 бит красного цвета 6 бит зеленого и 5 бит синего цвета. В таком-же формате их и следует вставить в бмп картинку, после шапки. Откуда вы взяли 32 бита непонятно.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
swat24    9

У меня функция возвращает 32 бита, т.е. получается два пикселя. Я их и запихиваю в бмп...

С камерами никогда не работал, поэтому и вопросов куча)

в файле получается такое:

cameraData.gif

Изменено пользователем swat24

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
swat24    9

В примере для камеры настраивается DMA на 32 бита источника и 16 бит приемник и отправляется на экран. Я считаю 2 байта на пиксель, так как выводится на экран, и буду отправлять попиксельно в юарт. Правильно? Вопрос как записывать в файл BMP? "00 00 ст мл" ? (ст - старший байт, мл - младший байт) или без пустых байт в начале?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
andryxa    232

в файл нужно писать так-же как читаете но есть один нюанс, после шапки должен быть конец массива картинки, а в конце файла начало. короче массив данных полученных с камеры нужно каким-то образом развернуть и только после этого создать картинку

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
swat24    9

хорошо, получается в шапке я указываю начало картинки и с этого адреса шлю "ст"+"мл" байты и так всю картинку, правильно? Если даже не переворачивать массив - то картинка будет перевернута, но должна быть. Еще в файле после массива данных идет массив нулей, попробовал его убрать - ругается на то, что файл поврежден. Его оставляю?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
andryxa    232

нет, прочитанный массив нужно целиком перевернуть потому-что пиксель состоит из двух байт и у вас все перемешается. и только после переворота вставлять в картинку

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
swat24    9

я понял.

В общем нашел пример сохранения BMP в формате 565 на JAVA:

public static void main( final String[] args ) {
        BufferedImage img = map( 320, 240 );
        savePNG( img, "C:/test.bmp" );
    }

    private static BufferedImage map( int sizeX, int sizeY ){
        final BufferedImage res = new BufferedImage( sizeX, sizeY, BufferedImage.TYPE_USHORT_565_RGB );
        for (int x = 0; x < sizeX; x++){
            for (int y = 0; y < sizeY; y++){
                res.setRGB(x, y, Color.WHITE.getRGB() );
            }
        }
        return res;
    }

    private static void savePNG( final BufferedImage bi, final String path ){
        try {
            RenderedImage rendImage = bi;
            ImageIO.write(rendImage, "bmp", new File(path));
        } catch ( IOException e) {
            e.printStackTrace();
        }
    }

это работает, допишу завтра прием по юарт и попробую. Должно быть следующее:

шапка:

42 4d 42 58 02 00 00 00 00 00 42 00 00 00 28 00
00 00 40 01 00 00 f0 00 00 00 01 00 10 00 03 00
00 00 00 58 02 00 00 00 00 00 00 00 00 00 00 00
00 00 03 00 00 00 00 f8 00 00 e0 07 00 00 1f 00
00 00

далее принятый массив читаю с конца и пишу в файл, начиная с 42 байта с помощью:

res.setRGB(x, y, Color.WHITE.getRGB() );

только вместо "Color.WHITE.getRGB()" принятые данные.

 

Спасибо, что помогаете :) Завтра буду пробовать и отпишусь о результате

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Ваша публикация должна быть проверена модератором

Гость
Вы не авторизованы. Если у вас есть аккаунт, пожалуйста, войдите.
Ответить в тему...

×   Вставлено в виде отформатированного текста.   Восстановить форматирование

  Разрешено не более 75 смайлов.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставить изображения напрямую. Загрузите или вставьте изображения по ссылке.

Загрузка...

  • Похожие публикации

    • Автор: michaelukolov
      Доброго времени суток.
      Сразу скажу: я не прошу писать за меня код, просто натолкните, как правильнее это реализовать.
      Имеется STM32F103C8T6, необходимо на ней построить одноканальный генератор сигнала, желательно разной формы (синус/меандр) с регулировкой частоты и скважности от переменного резистора. Регулировки частоты хватило бы в пределах 1Гц - 20кГц (отсюда еще вопрос, годится ли для этого F103C8T6?). Хотелось бы еще иметь разные уровни (5В/12В), но это и сам сообразить могу.
      Если использовать HAL таймер, то когда он уже будет запущен, можно будет менять частоту/скважность?
      Как реализовать переключение синус/меандр?
    • Автор: artos5
      Всем привет! Столкнулся с проблемой которую не удается решить.
      прописал в файле Drive.h так:
      typedef struct { uint8_t FlgL; uint8_t FlgR; uint16_t Speed; uint16_t PulseL1; uint16_t PulseL2; uint16_t PulseR1; uint16_t PulseR2; } Motor_; typedef struct { uint8_t Status; } Button_; extern struct Motor_ Motor; extern struct Button_ Button; а в с файле:
      #include "Drive.h" Motor.Pulse = 3; // зададим значение переменной в структуре Motor в итоге 2 ошибки редефайн....
       
      как правильно с ними работать? За вчера и за сегодня уже наверное 1000 вариантов попробовал.
    • Автор: artos5
      Всем доброго времени суток!
      Необходима стабилизация частоты вращения двигателей по энкодерам. Энкодеры состоят из одного датчика холла на валу двигателя.
      Эту задачу на АВР я решил при помощи INT0 и аппаратного таймера , попробовал перенести код на STM32 . Попробовал через EXTI , результат не понравился .. Решил через таймер .
       
      void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { static uint8_t InpCaptIndexL=0, InpCaptIndexR=0; if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) // =RISING= EDGE DETECTED { // Get =RISING= EDGE Capture value if(InpCaptIndexR==0) { Motor.TimerOldR = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); InpCaptIndexR=1; } else { Motor.TimerNewR = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); InpCaptIndexR=0; } if (Motor.TimerOldR > Motor.TimerNewR) { Motor.MotorRData = (Motor.TimerOldR - Motor.TimerNewR); } else { Motor.MotorRData = (Motor.TimerNewR - Motor.TimerOldR); } // Reset Counter After Input Capture Interrupt Occurs __HAL_TIM_SET_COUNTER(&htim1,0x00); } if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) // =FALLING= EDGE DETECTED { // Get =FALLING= EDGE Capture value if(InpCaptIndexL==0) { Motor.TimerOldL = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2); InpCaptIndexL=1; } else { Motor.TimerNewL = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2); InpCaptIndexL=0; } if (Motor.TimerOldL > Motor.TimerNewL) { Motor.MotorLData = (Motor.TimerOldL - Motor.TimerNewL); } else { Motor.MotorLData = (Motor.TimerNewL - Motor.TimerOldL); } // Reset Counter After Input Capture Interrupt Occurs } StabMotorSpeed1(); __HAL_TIM_SET_COUNTER(&htim2, 0x00); } в интернете подсмотрел применение захвата но получается какая то каша . Осциллографом четко вижу меандр одинаковой частоты , а в юарт сыпет постоянно разные значения ...
      (имею ввиду переменную Motor.MotorLData и Motor.MotorRData)
      Тактирование 64МГц
      настройки таймера такие:
      TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_IC_InitTypeDef sConfigIC = {0}; htim2.Instance = TIM2; htim2.Init.Prescaler = 6400; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 65535; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim2) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } if (HAL_TIM_IC_Init(&htim2) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { Error_Handler(); } sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; sConfigIC.ICFilter = 0; if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK) { Error_Handler(); } if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_2) != HAL_OK) { Error_Handler(); } что то я или недопонимаю , или что то не так приготавливаю..
       
      Пробовал и так:
      void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) // =RISING= EDGE DETECTED { // Get =RISING= EDGE Capture value Motor.TimerR = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2); // Reset Counter After Input Capture Interrupt Occurs __HAL_TIM_SET_COUNTER(&htim1,0x00); } if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) // =FALLING= EDGE DETECTED { // Get =FALLING= EDGE Capture value Motor.TimerL = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); // Reset Counter After Input Capture Interrupt Occurs } StabMotorSpeed(); __HAL_TIM_SET_COUNTER(&htim2, 0x00); } Результат тоже хуже чем на АВР , и в юарт сыпет каша (имею ввиду переменную Motor.TimerL и Motor.TimerR)
      Помогите пожалуйста разобраться в чем дело.
    • Автор: Grampus
      Добрый день!
      ПОМОГИТЕ ПОЖАЛУЙСТА!
      в описании для одного дисплея нашел код для STM на СИ
      там есть строчка которая мне не понятна, точнее смысл ее понятен но нет объявления аргументов функции
      помогите пожалуйста. В общем ситуация такая 
       
      spi_write ( DTA, 0x00 )                                     spi_write ( CMD, 0x01) 
      вот эта функция
      DTA - выполняет установку пина в 1 ,    CMD -  выполняет установку пина в 0 
      0x00 , 0x01, .........0xFF     это либо данные либо команда. 
       и все бы ничего но все это нужно передать по HAL_SPI_Transmit 
      помогите написать эту функцию с описанием аргументов и всех действий.
    • Автор: Mars36
      Добрый день. Имею желание вкатиться в разработку на stm32. Не много погуглив обнаружил копеечный программатор(tt-link), но отладочной платы как у какой нибудь avr'ки не нашел(аля вставил камень, прошил, впаял в плату). Существует множество всяких discovery  и им подобных, для проверки работы штука удобная, но для использовании в конечном устройстве нерациональная. Поэтому хотелось бы знать, существуют ли какие либо платы, переходники и т.д.? И если подобных промышленных вариантов нету, то единственный вариант это развести такую самостоятельно и вкорячивать переходники c LQFPхх и т.д.?
      P.S. Когда то видел вариант у аврки c tqfp корпусом, когда к подобной домашней плате аврку цепляли с помощью прищепки.
  • Сообщения

    • Ну раз уж несколько раз перечитал, тада пардонь мура ми - невзначай, как тому старому цепному псу, как-то подумалось, что ещё один "джекпатрашитель" решил обкоцать эту балалайку.  Кстати, тема волей админ-а  слеплена из двух, и если ты действительно всё несколько раз перечитал, мог бы заметить, что в старт-посте есть ссыль на то, с чего всё началось. Изначально предтече "минуетика" , версия Вадика, назывался "мойпуссик"(по англицки ест-но  ), и у меня была мысль оставить это название; а "минуэтик" начался позже, и потому вырос несколько иным. Без драйверной пары - это не "минуетик", а только лишь "пупсик".()  Пробуй конечно, решай свои задачи - не запрещается. Просто мне не хочется, что бы кто-то ломал то, что уже сделано(при чём сделано довольно-таки неплохо и отработано на практике) а потом, при собственной неудачи, кидался бы валенком в адрес тех, кто дал жизнь этой балалайке. Удачи. Если будут трудности, обращайся.
    • Кто подскажет, при включении фена, температура сразу прет до 600, спасает только геркон с магнитом, если бы семистор пробил, грело бы и на падставке...
    • Имеется Литий ионный аккумулятор 3.7в со встроенным контроллером. Для его зарядки достаточно подать напряжение, или же необходима эта схема. И никак не вЪеду какое напряжение нужно подавать для его зарядки, 5в или 3.3в
    • Вот так просто? Не знаю, что за усилитель, предположу по фотографии: 1. В усилителе изначально стояли кт819, при ремонте из заменили на кт837. Запустился ли он после этого - кто знает? 2. На плате один канал 3. На плате трансформатор. Или выходной или межкаскадный. В любом случае, качества от усилителя ждать не стоит. Вероятно, усилитель от какой то громкоговорящей приставки: мегафон, усилитель, чтобы объявлять остановки в автобусе и т.д. 4. Конденсаторы на плате уже потеряли ёмкость Из ценного, в нём: радиатор и с некоторой натяжкой кт 818, и то, если живые. В общем, возиться с ним - терять время.  
    •  к оцинкованому  железу (жести) 40-ка лучше "липнет".  В остальном, 61-ка предпочтительней (с канифолью и без). С уважением, Сергей  
    • А зачем вам марка? подключите питание и наслаждайтесь