Questão:
Como ler imagens de bitmap no Arduino
Seawish
2016-01-21 13:35:15 UTC
view on stackexchange narkive permalink

Quero converter um bitmap em matriz binária. Minha imagem bitmap é uma imagem monocromática de 1bpp de 272 * 208 pixels. Estou confuso quando a largura que obtenho da minha imagem é 16 em vez de 272, a altura foi corrigida. E quando pulo o cabeçalho do bitmap para obter informações sobre o bitmap, recebo uma string de número sem sentido no meu arquivo de texto.

  #include <SPI.h> # include <SD.h> # include <TFT.h>File bmpImage; File textFile; void setup () {Serial.begin (9600); while (! Serial) {;} Serial.print ("Inicializando o cartão SD ...") SD.begin (53)) {Serial.println ("inicialização falhou!"); return;} Serial.println ("inicialização concluída."); int height = 0; int largura = 0; // OpenbmpImage = SD.open ("Circle.bmp", FILE_READ); textFile = SD.open ("teste. txt ", FILE_WRITE); bmpImage.seek (0x12); // largura em pixel = 16width = bmpImage.read (); bmpImage.seek (0x16); // altura em pixel = 208height = bmpImage.read (); Serial. println (largura); Serial.println (altura); int tamanho da imagem = altura * largura; bmpImage.seek (0x36); // ignorar cabeçalho de bitmap para (int i = 0; i < altura; i ++) {para (int j = 0; j < largura; j ++) {textFile.write (bmpImage.read ()); textFile.write (""); } textFile.write ("\ n");} bmpImage.close (); textFile.close (); Serial.println ("done write");} void loop () {// nada acontece após a configuração}  
Trzy respostas:
Mikael Patel
2016-01-21 15:41:56 UTC
view on stackexchange narkive permalink

Essa foi uma maneira muito simples de tentar ler um arquivo BMP. Existem muitas suposições que podem gerar erros.

  1. O arquivo é um arquivo BMP. A assinatura do cabeçalho não é verificada.
  2. O deslocamento da imagem é considerado imediatamente após o cabeçalho do arquivo. Não é lido.
  3. A largura da imagem é menor que 256. Somente o byte mais baixo da largura da imagem de 32 bits é lido. Como 272> 256, o byte inferior é 16.
  4. A altura da imagem é menor que 256. Apenas o byte inferior da altura da imagem de 32 bits é lido.

É um bitmap pequeno, mas levará muito tempo para ler ao ler um único byte por vez. Existem métodos para melhorar o desempenho, mas essa é a resposta a outra pergunta.

Um método mais robusto para ler o cabeçalho BMP e as informações da imagem é defini-los como uma estrutura e ler.

  struct bmp_file_header_t {assinatura uint16_t; uint32_t file_size; uint16_t reservado [2]; uint32_t image_offset;}; struct bmp_image_header_t {uint32_t header_size; uint32_t image_width; uint32_t image_height; uint16_t color_planes; uint16_t bits_per_pixel; uint32_t compression_method; uint32_t image_size; uint32_t horizontal_resolution; uint32_t vertical_resolution; uint32_t colors_in_palette; uint32_t important_colors;}; bmpImage = SD.open ("Circle.bmp", FILE_READ); ... // Ler o arquivo headerbmp_file_header_t fileHeader; bmpImage.read (&fileHeader, sizeof (fileHeader)); ... // Verificar assinatura ... // Leia a imagem headerbmp_image_header_t imageHeader; bmpImage.read (&imageHeader, sizeof (imageHeader)); ... // Verifique o tamanho e formato da imagem ... // Localize os pixelsbmpImage.seek (fileHeader.image_offset); / code> 

As informações do arquivo e da imagem são armazenadas no little-endian para que funcione bem em um AVR.

frarugi87
2016-01-21 15:42:06 UTC
view on stackexchange narkive permalink

Em primeiro lugar, sugiro que você leia a especificação completa do cabeçalho do arquivo bmp (por exemplo, na wikipedia).

Em particular, veja que

  1. Você pode ter uma tabela de cores (paleta): consequentemente, o endereço inicial dos dados de bitmap não pode ser 0x36
  2. Os pixels não são armazenados um por byte, mas podem ser compactados (consulte Armazenamento de pixels)
  3. Existem diferentes tipos de cabeçalhos
  4. Largura e Altura são inteiros de 4 bytes, então sua largura é boa (272 = 256 + 16)

Dito isso, se seu bitmap tem um cabeçalho BITMAPINFOHEADER padrão e se seu bitmap tem um padrão de 24 bits codificação (16 milhões de cores), você pode fazer algo assim:

  int32_t readNbytesInt (Arquivo * p_file, posição int, byte nBytes) {if ( nBytes > 4) return 0; p_file->seek (posição); peso_int32_t = 1; int32_t result = 0; for (; nBytes; nBytes--) {resultado + = peso * p_file->read (); peso << = 8; } resultado de retorno;} void setup () {Serial.begin (9600); while (! Serial); Serial.print ("Inicializando o cartão SD ..."); if (! SD.begin (53)) {Serial.println ("a inicialização falhou!"); enquanto (1); // <- é assim que você deve bloquear a execução, não com retornos} Serial.println ("inicialização concluída."); // Abrir o arquivo bmpImage = SD.open ("Circle.bmp", FILE_READ); Arquivo textFile = SD.open ("test.txt", FILE_WRITE); int32_t dataStartingOffset = readNbytesInt (&bmpImage, 0x0A, 4); // Altere seus tipos para int32_t (4byte) int32_t width = readNbytesInt (&bmpImage, 0x12, 4); int32_t height = readNbytesInt (&bmpImage, 0x16, 4); Serial.println (largura); Serial.println (altura); int16_t pixelsize = readNbytesInt (&bmpImage, 0x1C, 2); if (pixelsize! = 24) {Serial.println ("A imagem não é 24 bpp"); enquanto (1);
} bmpImage.seek (dataStartingOffset); // ignorar cabeçalho de bitmap // 24bpp significa que você tem três bytes por pixel, geralmente B G R byte R, G, B; for (int32_t i = 0; i < height; i ++) {for (int32_t j = 0; j < largura; j ++) {B = bmpImage.read (); G = bmpImage.read (); R = bmpImage.read (); textFile.print ("R"); textFile.print (R); textFile.print ("G"); textFile.print (G); textFile.print ("B"); textFile.print (B); textFile.print (""); } textFile.print ("\ n"); } bmpImage.close (); textFile.close (); Serial.println ("done write");}  

A saída de texto deste deve ser um arquivo com uma matriz de strings como R10G100B25 , onde R é o o componente vermelho do pixel, G é o componente verde e B o azul.

Agora, isso só é compatível com o formato 24bpp. Se desejar oferecer suporte a mais formatos, você precisará ler as especificações e codificá-los.

Me diga se isso funciona para você

SoreDakeNoKoto
2016-01-21 20:02:18 UTC
view on stackexchange narkive permalink

Ou você pode manter seu código antigo com alguns ajustes, se quiser apenas ler sua imagem sem se preocupar com muitas verificações.

Altere o tipo de tamanho da imagem para unsigned long .

A altura e a largura são campos de 4 bytes, portanto, um único read () não os cortará. Você deve declarar a altura e a largura como variáveis ​​ long ou int32_t e, em seguida, ler 4 bytes em cada deslocamento, enquanto usa o deslocamento de bits para montar os bytes em um número e lembrar que é um pequeno endian. Algo assim:

  long width | = bmpImage.read (); width | = (long) (bmpImage.read ()) << 8; width | = (long) (bmpImage.read ()) << 16; largura | = (longo) (bmpImage.read ()) << 24;  

Repita para obter a altura, mas use abs ( ) para obter o valor absoluto, já que geralmente é negativo. Você também pode verificar se há uma tabela de cores; geralmente o campo ColorDepth é um bom indicador (deslocamento 28); se for menor que 16, você deve esperar uma tabela de cores. Mas se você já sabe disso, pode pular e ir para o deslocamento inicial, geralmente 0x36. Seu código atual não leva em consideração o preenchimento (mesmo que sua imagem não tenha nenhum preenchimento) e também não está usando a imagem real largura em bytes. Para obter essa largura, supondo que o BMP use RGB888 24 bits por pixel:

  width = ((width * 24) + 31) / 32; width * = 4;   pré>

Com isso, agora você pode ler cada linha, embora esteja geralmente organizada de baixo para cima. No entanto, você não está gravando corretamente no arquivo. Você deve usar textfile.print () e não write () ; o primeiro gravará o valor decimal de cada byte em seu arquivo, enquanto o último gravará o byte não codificado exato no arquivo de texto, o que resultaria em muitos rabiscos ao tentar exibir o conteúdo do arquivo, digamos no Bloco de notas, já que o intervalo de caracteres imprimíveis (sob a codificação ASCII padrão) está entre 32 - 127 e sua imagem provavelmente tem muitos bytes fora desse intervalo.



Estas perguntas e respostas foram traduzidas automaticamente do idioma inglês.O conteúdo original está disponível em stackexchange, que agradecemos pela licença cc by-sa 3.0 sob a qual é distribuído.
Loading...