Pois bem. Fazendo daquela maneira, há certos problemas: ambos objetos devem permanecer vivos, e o dono dos pixels tem que ser a IplImage.
Isto pode não ser desejado. Por exemplo, vou citar o caso que aconteceu comigo e tive que matar um pouco a cabeça para resolver.
Muitas imagens que eu exibo (com o FOX Toolkit) precisam antes passar por algum processamento (com o OpenCV). Depois disso, eu não preciso mais da IplImage, apenas dos pixels.
Entretanto, seguir os passos explicados no outro tópico levava a um problema seriíssimo, que será explicado no decorrer deste tópico.
Compartilhando pixels: antigamente
Conforme eu havia explicado, criava-se primeiro a IplImage e depois a FXImage, utilizando o vetor de pixels, mais ou menos assim:
IplImage *iplImage = cvCreateImage(cvSize(200, 200), IPL_DEPTH_8U, 4); FXImage *fxImage = new FXImage(getApp(), iplImage->imageData, IMAGE_KEEP|IMAGE_OWNED|IMAGE_SHMP|IMAGE_SHMI, iplImage->width, iplImage->height);
Lembrando que era necessário um cast horroroso com reinterpret_cast para transformar os pixels da IplImage de char* para FXColor.
Com isso, eu tenho que minha IplImage "doou" seus pixels para a FXImage, que tomou conta deles. Assim, a IplImage poderia ser dispensada (na verdade, somente o cabeçalho da imagem; o OpenCV permite isso) que a FXImage, quando for liberada, libera também o vetor de pixels.
O problema
Isso causa um problema que eu demorei muito para descobrir. E, depois de descoberto, vê-se que é uma coisa tão simples... é sempre um detalhezinho que cega a gente.
O grande problema é que, como o vetor de pixels é alocado pela IplImage, ele é alocado usando malloc. A FXImage, quando tenta liberar, tenta com delete. Aí não dá certo...
A "solução"
Eu criava as imagens independentemente, cada uma com seu vetor de pixels. Depois de processada, eu fazia uma chamada a memcpy para copiar os pixels. Uma tristeza considerando o contexto.
Compartilhando pixels: a solução de fato
Depois de quase desistir da idéia, eu descobri (dia desses...) o problema. E logo cheguei a uma solução elegante (e óbvia).
Basta criar primeiro a FXImage, que vai apenas "emprestar" os pixels para a IplImage. Assim:
FXImage *fxImage = new FXImage(getApp(), 0, IMAGE_KEEP|IMAGE_OWNED|IMAGE_SHMP|IMAGE_SHMI, 200, 200);
Percebam que o segundo parâmetro, que seria o vetor de pixels, é nulo. Como os pixels são de responsabilidade da FXImage, ela mesma os cria (isso é informado pela opção IMAGE_OWNED).
É necessário também manter os pixels no lado do cliente (opção IMAGE_KEEP). Sem ela, os pixels são liberados depois da imagem criada, impossibilitando o compartilhamento.
Pois bem, agora vamos "emprestar" os pixels da FXImage para a IplImage:
IplImage *iplImage = cvCreateImageHeader(cvSize(200, 200), IPL_DEPTH_8U, 4); cvSetData(iplImage, fxImage->getData(), CV_AUTOSTEP);
cvCreateImageHeader() aloca todas as informações de uma imagem, com exceção do vetor de pixels. Com isso, a IplImage, que é temporária, apenas pega emprestado os pixels para trabalhar sobre eles. Ao terminar o processamento, podemos liberar o cabeçalho:
cvReleaseImageHeader(&iplImage);
Uma grande vantagem dessa abordagem é que não precisa nem converter a imagem, conforme eu havia feito anteriormente. A imagem já é criada no formato da FXImage.
Conclusão
Conforme havia dito, é uma coisa tão simples e óbvia que fica invisível.
Espero que essa informação seja útil para quem for usar essas duas bibliotecas juntas.
Abraço e até a próxima.
Nenhum comentário:
Postar um comentário