v0.26 — Edição de 2026. Um currículo de 5 episódios sobre a utilização do scikit-image v0.26 (Edição de 2026) como motor central de pré-processamento de imagens e data augmentation em pipelines modernos de IA e deep learning.
Processamento de ImagemCiência de DadosVisão Computacional
Descubra como o scikit-image representa imagens como ndarrays do NumPy. Saiba por que motivo este design o torna no motor de pré-processamento perfeito para frameworks de deep learning como o PyTorch e o TensorFlow.
4m 24s
2
Falar a Mesma Língua: Dtypes e OpenCV
Domine os tipos de dados de imagem para evitar os bugs silenciosos mais comuns em visão computacional. Aprenda a integrar perfeitamente o scikit-image com o OpenCV e os inputs de redes neuronais.
4m 34s
3
Contraste, Exposição e Robustez da IA
Aprenda a utilizar o ajuste de contraste e a equalização de histogramas para padronizar datasets. Estas técnicas são cruciais para tornar os modelos de IA robustos face a condições de iluminação variáveis.
4m 20s
4
Transformações Geométricas para Data Augmentation
Explore como redimensionar imagens para se ajustarem aos inputs das redes neuronais e aplicar transformações affine. Essencial para construir pipelines robustos de data augmentation.
4m 16s
5
Segmentação Clássica para Impulsionar a IA
Descubra como utilizar a segmentação clássica watershed para gerar automaticamente máscaras de treino com precisão ao nível do píxel para modelos de deep learning, poupando horas de anotação manual.
3m 51s
Episódios
1
O Pipeline de Imagens de IA: NumPy no Núcleo
4m 24s
Descubra como o scikit-image representa imagens como ndarrays do NumPy. Saiba por que motivo este design o torna no motor de pré-processamento perfeito para frameworks de deep learning como o PyTorch e o TensorFlow.
Olá, daqui é o Alex da DEV STORIES DOT EU. scikit-image: O AI Image Pipeline, episódio 1 de 5. Antes que um modelo de deep learning consiga reconhecer uma cara, tem de digerir uma grelha de números. Se alimentares essa grelha na ordem errada, o teu modelo não aprende nada e o teu processamento fica extremamente lento. O AI Image Pipeline: NumPy at the Core é a solução para estruturar essa grelha corretamente.
Quando carregas uma imagem usando o scikit-image, não recebes um objeto de imagem proprietário. Recebes um array N-dimensional standard, conhecido como ndarray. Uma imagem é simplesmente uma matriz de pixels. Como é um simples array NumPy, podes usar qualquer operação standard para fazer slice, mask, ou manipular os dados da imagem diretamente.
Aqui está o ponto chave. A forma como o scikit-image indexa estes arrays confunde muitos developers. Na geometria standard, usas coordenadas x e y, onde o x é horizontal e o y é vertical. O scikit-image abandona isto em favor da notação matricial. O primeiro index é a row, que corresponde à posição vertical. O segundo index é a column, que corresponde à posição horizontal. Se tiveres uma imagem a cores, o terceiro index é o channel de cor. Uma imagem a cores bidimensional standard é, na verdade, um array tridimensional ordenado como row, column, channel.
Supõe que estás a preparar um batch de imagens a cores para alimentar uma Convolutional Neural Network. A tua rede espera um shape específico. Se a tua imagem tiver 256 pixels de altura e 256 pixels de largura, com channels vermelho, verde e azul, o shape de uma única imagem é 256, 256, 3. Mas um batch destas imagens adiciona uma quarta dimensão no início, que representa o número de imagens.
Quando aplicas funções do scikit-image a estes dados, a função precisa de saber qual é a dimensão que contém os valores de cor, para não os processar como dados espaciais. Isto é tratado pelo argumento channel axis. Ao definires o argumento channel axis para menos um, dizes à função que os channels de cor estão sempre na última dimensão do array. Isto garante que a função utiliza os dados de cor corretos, independentemente de lhe passares uma única imagem ou um grande batch com dimensões espaciais extra.
Isto leva-nos à memória. Esta é a parte que importa para a velocidade de processamento. Os arrays NumPy são armazenados em blocos contíguos de memória, usando uma ordem tipo C por default. Isto significa que a última dimensão no shape do array é a que muda mais rapidamente na memória física. Para o nosso array de imagem standard de row, column, channel, os channels de cor individuais de um único pixel ficam lado a lado na tua RAM de hardware.
Se escreveres código custom para fazer um loop sobre estes pixels, tens de respeitar este memory layout. A regra é absoluta: a dimensão mais à direita do teu array deve ser processada no loop mais interno. Iteras sobre as rows no loop exterior, depois as columns, e depois os channels no interior. Se inverteres isto e fizeres o loop sobre as rows no interior, forças o CPU a saltar de um lado para o outro por endereços de memória fragmentados. Isto destrói a cache locality e faz com que o teu código corra significativamente mais devagar.
A coisa mais crítica a lembrar é que o scikit-image não usa coordenadas horizontais e verticais; usa uma indexação matricial estrita de row, column, e channel, e alinhar os teus loops com essa ordem exata de memória é o que mantém o teu data pipeline rápido.
Se quiseres ajudar a manter este podcast no ar, podes apoiar o programa procurando por DevStoriesEU no Patreon. É tudo por este episódio. Obrigado por ouvires, e continua a programar!
2
Falar a Mesma Língua: Dtypes e OpenCV
4m 34s
Domine os tipos de dados de imagem para evitar os bugs silenciosos mais comuns em visão computacional. Aprenda a integrar perfeitamente o scikit-image com o OpenCV e os inputs de redes neuronais.
Olá, daqui é o Alex da DEV STORIES DOT EU. scikit-image: O pipeline de IA para imagens, episódio 2 de 5. O bug silencioso mais comum em IA de visão computacional não está na arquitetura da rede neural. É uma incompatibilidade de data types. Alimentas um modelo com uma imagem, o código corre sem dar erros, mas os outputs são puro lixo. Isto acontece quando as tuas libraries discordam fundamentalmente sobre como um pixel deve ser representado numericamente. Hoje, vamos corrigir isto abordando o tema Falar a Mesma Língua: Dtypes e OpenCV.
No scikit-image, as imagens são guardadas como arrays numpy standard. Mas os números dentro desses arrays comportam-se de maneira diferente dependendo do seu data type exato. O formato default de webcams e ficheiros de imagem standard é o inteiro sem sinal de oito bits, conhecido como uint8. Estes valores vão de zero a 255, onde zero é o preto absoluto e 255 é a intensidade máxima.
No entanto, funções de processamento de imagem científica e frameworks de deep learning quase sempre preferem números de ponto flutuante. No scikit-image, uma imagem float espera que as intensidades dos pixels sejam escaladas num range estrito, geralmente de zero a um.
Aqui está o ponto chave. Não uses o método astype do numpy para converter as tuas imagens uint8 em floats. Se pegares num array uint8 e simplesmente chamares astype float, o numpy apenas altera o tipo de memória subjacente. Um valor de pixel brilhante de 255 torna-se simplesmente 255 ponto zero. Não faz o rescale dos valores. Se passares esse array para uma função do scikit-image ou para um modelo de PyTorch que espera um brilho máximo de um ponto zero, a matemática rebenta. Os teus brancos são de repente tratados como se fossem 255 vezes mais brilhantes do que o valor máximo possível.
Em vez disso, deves usar as funções utilitárias built-in do scikit-image. A mais importante chama-se img_as_float. Esta função verifica o data type de input e lida com o rescale matemático automaticamente. Comprime com segurança um range uint8 de zero a 255 para um range float preciso de zero a um ponto zero.
Os data types são apenas metade da batalha. Também tens de alinhar os canais de cor, especialmente se estiveres a capturar vídeo. Se leres um frame usando o OpenCV, ele entrega-te um array numpy uint8. Mas o OpenCV tem uma peculiaridade histórica. Guarda os canais de cor na ordem Blue Green Red, conhecida como BGR. O scikit-image e a maioria dos modelos de IA modernos esperam Red Green Blue, ou RGB. Se te esqueceres de trocar os canais, maçãs vermelhas parecem azuis e a pele humana parece completamente extraterrestre.
Não precisas de chamar uma função pesada de conversão de cores do OpenCV para corrigir isto. Como a imagem é apenas um array numpy, podes usar array slicing básico. Fazes o slice do array nas suas três dimensões. Pegas em todas as linhas, todas as colunas e, para a dimensão final que representa os canais de cor, especificas um step de menos um. Isto diz ao numpy para fazer o step para trás através dos canais, revertendo BGR para RGB instantaneamente na memória.
Vamos percorrer um pipeline de ingestão completo para um modelo de deep learning. Primeiro, capturas um frame de uma video stream do OpenCV, dando-te um array BGR uint8. A seguir, invertes os canais de cor usando numpy slicing para o converteres para RGB. Depois, passas esse array para o img_as_float. O array é agora uma matriz de ponto flutuante, perfeitamente escalada entre zero e um. Finalmente, convertes este array numpy limpo num tensor de PyTorch.
Uma rede neural não te consegue dizer quando os seus dados de input estão escalados incorretamente, ela simplesmente aprende os padrões errados ou falha silenciosamente. Controlar os teus data types e a ordem dos canais logo na etapa de ingestão garante que o teu pipeline assenta numa base matemática sólida.
É tudo por este episódio. Obrigado por ouvires, e continua a programar!
3
Contraste, Exposição e Robustez da IA
4m 20s
Aprenda a utilizar o ajuste de contraste e a equalização de histogramas para padronizar datasets. Estas técnicas são cruciais para tornar os modelos de IA robustos face a condições de iluminação variáveis.
Olá, daqui é o Alex do DEV STORIES DOT EU. scikit-image: O pipeline de IA para imagens, episódio três de cinco. As redes neuronais são excelentes a encontrar padrões, mas memorizam facilmente a iluminação específica de uma sala em vez do objeto que tu queres que elas detetem. Para corrigir isto, precisamos de padronizar a variância nos nossos datasets através de Contraste, Exposição e Robustez da IA.
Considera um dataset de radiografias médicas recolhidas numa dúzia de hospitais diferentes. Os scans vêm de máquinas diferentes com calibrações muito variadas. Algumas imagens são escuras e turvas, enquanto outras são desbotadas e brilhantes. Se alimentares estes dados raw numa rede neuronal, ela provavelmente vai fazer overfit às condições de iluminação de scanners específicos, em vez de aprender a identificar a patologia subjacente. Tens de normalizar a exposição antes de o treino começar.
O primeiro passo nesta padronização é, muitas vezes, remover informação irrelevante. Se a estrutura é tudo o que importa, a cor é uma distração. Podes usar uma função chamada rgb to gray para converter imagens coloridas em arrays grayscale de um só canal. Isto reduz a dimensionalidade dos teus dados e força o modelo a avaliar a luminância pura.
Assim que estiveres a trabalhar estritamente com luminância, precisas de alinhar o brilho de base em todo o teu dataset. É aqui que entra o rescale intensity. Esta função faz um linear stretch aos dados da tua imagem. Ela pega no pixel mais escuro e mapeia-o para o valor mais baixo possível, como zero, e mapeia o pixel mais brilhante para o valor mais alto possível, como duzentos e cinquenta e cinco. Todos os pixels intermédios são escalonados linearmente.
Aqui está o ponto chave. Um simples stretch de mínimo ao máximo é frágil. Um único pixel preto morto ou um artefacto brilhante causado por uma partícula de pó no sensor vai ditar toda a escala. O stretch vai comprimir os teus dados anatómicos reais numa faixa estreita e inútil de tons de cinzento apenas para acomodar esse outlier extremo.
Para resolver isto, usas percentile clipping. Em vez de fazeres o stretch a partir do mínimo e máximo absolutos, calculas o segundo e o nonagésimo oitavo percentis dos valores dos pixels na tua imagem. A seguir, passas esses percentis para a função rescale intensity como o teu input range. A função vai cortar os dois por cento extremos de pixels claros e escuros, definindo-os como branco puro e preto puro, e fazer um linear stretch aos restantes noventa e seis por cento dos dados. Isto garante que a maior parte dos teus dados estruturais usa todo o dynamic range, ignorando completamente artefactos aleatórios.
Às vezes, um linear stretch não é suficiente. Podes ter uma radiografia onde os dados são capturados, mas todos os pixels estão agrupados à volta de alguns tons específicos de cinzento, fazendo com que a imagem pareça plana e obscurecendo os detalhes. Para isto, usas o equalize hist, que significa histogram equalization.
O histogram equalization é um processo não linear. Em vez de apenas fazer o stretch dos limites, analisa a frequência de cada valor de pixel na imagem. A seguir, distribui os valores de intensidade mais frequentes por todo o espectro disponível. Se uma grande parte da tua radiografia estiver presa numa faixa estreita de cinzentos escuros, o histogram equalization vai separar esses cinzentos, atribuindo-lhes novos valores que vão do preto ao branco. Isto aumenta artificialmente o contraste local, revelando texturas e contornos subtis que antes estavam ocultos nas áreas turvas do scan.
Padronizar o teu dataset com estas técnicas garante que o teu modelo avalia a forma e a textura reais do objeto. Um pipeline robusto remove a variância irrelevante da calibração de hardware, forçando a rede neuronal a aprender o sinal em vez do ruído. Obrigado por passares uns minutos comigo. Até à próxima, fica bem.
4
Transformações Geométricas para Data Augmentation
4m 16s
Explore como redimensionar imagens para se ajustarem aos inputs das redes neuronais e aplicar transformações affine. Essencial para construir pipelines robustos de data augmentation.
Olá, daqui fala o Alex da DEV STORIES DOT EU. scikit-image: A AI Image Pipeline, episódio 4 de 5. Uma rede neuronal convolucional pode reconhecer um gato perfeitamente. Mas vira esse gato de cabeça para baixo, ou desloca-o três pixels para a esquerda, e o modelo fica de repente completamente cego. Resolves isto com Transformações Geométricas para Data Augmentation.
Antes de fazermos qualquer augmentation, temos de preparar a baseline. As redes neuronais requerem input shapes fixos. Tratas disso usando a função resize no scikit-image. Passas-lhe uma imagem e as tuas target output dimensions, e ela estica ou encolhe matematicamente o pixel array para caber, interpolando os novos valores dos pixels automaticamente. Mas fazer apenas o resize deixa o teu modelo vulnerável a overfitting. Ele vai memorizar exatamente onde os objetos estão posicionados na frame. Para evitar isto, crias uma pipeline de data augmentation que aplica transformações aleatórias às training images on the fly.
No scikit-image, as transformações espaciais manipulam o espaço de coordenadas da imagem usando matemática de matrizes. Mover ou rodar uma imagem significa multiplicar as suas coordenadas de pixels por uma matriz de transformação. Aqui está a ideia principal. A translação, que é deslocar uma imagem ao longo do eixo x ou y, não pode ser calculada usando a multiplicação padrão de matrizes dois por dois. A multiplicação de matrizes lida com scaling e rotação, mas o deslocamento requer adição.
Para resolver isto, o scikit-image usa coordenadas homogéneas. Ao adicionar uma terceira coordenada fictícia, o número um, a cada ponto bidimensional, o sistema faz o upgrade à matemática. Isto permite que translações, rotações e scaling sejam todos calculados simultaneamente como uma única multiplicação de matrizes três por três.
Não precisas de escrever estas matrizes três por três manualmente. O scikit-image fornece classes de transformação para fazer os cálculos por ti. Para a nossa pipeline anti-overfitting, usas a classe Euclidean transform. Uma transformação euclidiana preserva distâncias e ângulos, o que significa que lida apenas com rotação e translação. Inicializas a classe passando-lhe um ângulo de rotação e um vetor de translação. Se precisasses de adicionar shearing ou alterar a scale, passarias para uma Affine transform. Se precisasses de simular uma mudança de perspetiva, usarias uma Projective transform. Mas para rotações e deslocamentos aleatórios, a Euclidean é exatamente o que precisas.
Uma vez definida a tua matriz de transformação, tens de a aplicar à tua imagem. Fazes isto usando a função warp. Passas à função warp a tua input image e o teu objeto Euclidean transform.
É aqui que a coisa fica interessante. A função warp não calcula para onde os input pixels devem ir na nova imagem. Se empurrares os pixels para a frente numa nova grid, a matemática da rotação cria coordenadas fracionárias. Quando estas são arredondadas para o pixel inteiro mais próximo, acabas com pixels em falta, ou buracos, espalhados pela tua output image. Em vez disso, o warp funciona ao contrário. Pega no inverso da tua matriz de transformação. Olha para cada coordenada de pixel vazia na target output image, mapeia-a para trás, para o espaço da imagem original, e interpola o valor de cor correto. Este inverse mapping garante um output sólido e sem buracos.
Para a tua pipeline de data augmentation, a lógica é simples. Gera um ângulo aleatório e um conjunto aleatório de deslocamentos. Passa-os para uma Euclidean transform. Passa essa transform e a tua training image para a função warp. O output vai diretamente para a tua rede neuronal. As transformações geométricas não criam apenas mais training data; elas forçam o teu modelo a separar o objeto que precisa de reconhecer das coordenadas arbitrárias que por acaso ocupa.
É tudo por este episódio. Obrigado por ouvires, e continua a desenvolver!
5
Segmentação Clássica para Impulsionar a IA
3m 51s
Descubra como utilizar a segmentação clássica watershed para gerar automaticamente máscaras de treino com precisão ao nível do píxel para modelos de deep learning, poupando horas de anotação manual.
Olá, daqui fala o Alex da DEV STORIES DOT EU. scikit-image: O pipeline de imagens de IA, episódio 5 de 5. Os modelos de segmentação de deep learning são incrivelmente poderosos, mas são incrivelmente gulosos. Eles exigem milhares de masks desenhadas à mão, pixel-perfect, antes de conseguirem aprender seja o que for. A segmentação clássica para fazer o bootstrap da IA preenche essa lacuna.
Estás a treinar uma U-Net moderna para detetar células ou moedas que se tocam. Precisas de labels de ground-truth. Desenhar estas masks à mão demora semanas. Podes tentar correr um detetor de edges simples, como o Canny, para automatizar o processo. O Canny é excelente a encontrar transições nítidas, mas muitas vezes falha a fechar os loops. Dá-te contornos fragmentados, e não regiões sólidas. Uma IA treinada com contornos quebrados vai gerar outputs de contornos quebrados.
A segmentação baseada em regiões resolve isto. Especificamente, o algoritmo Watershed. Ele trata a tua imagem como uma paisagem topográfica. Valores de pixel altos são montanhas, e valores baixos são vales. Aqui está o ponto-chave. Em vez de tentar ligar edges quebradas, o Watershed inunda a imagem a partir de pontos de partida conhecidos até que a água se encontre nas cristas mais altas. Isto garante regiões fechadas e sólidas.
Primeiro, constróis o terreno. Fazes isto gerando um mapa de elevação com um filtro Sobel. O filtro Sobel calcula gradientes espaciais, destacando as edges. Quando o aplicas à tua imagem, os limites entre as moedas sobrepostas tornam-se as cristas altas no teu mapa. As superfícies planas das moedas e o background passam a ser os vales.
A seguir, colocas os markers. Tens de dizer ao algoritmo onde a água deve começar a subir. Se saltares este passo, o algoritmo vai inundar a partir de cada pequeno mínimo local e fragmentar a tua imagem em centenas de fragmentos inúteis. Crias um array de markers exatamente do mesmo tamanho da tua imagem original. Encontras o background definitivo selecionando pixels abaixo de um threshold de intensidade específico e atribuis-lhes o valor um. Depois, encontras o foreground definitivo, que são os centros sólidos das moedas, selecionando pixels acima de um threshold de intensidade mais alto. A esses, atribuis o valor dois.
Finalmente, inicias a inundação. Passas o teu mapa de elevação e o teu array de markers para a função watershed do módulo de segmentação do scikit-image. O algoritmo preenche as regiões a começar pelos valores um e dois. À medida que a água simulada sobe, as regiões expandem-se. Quando finalmente se encontram nas cristas altas do mapa de elevação Sobel, o algoritmo constrói uma boundary.
A função devolve um array de inteiros de regiões fechadas e com labels perfeitas. Objetos que se tocam são separados exatamente na boundary. Agora tens um array de masks limpo, onde cada moeda é um objeto sólido distinto. Podes correr este pipeline em todo o teu dataset sem labels para gerar milhares de masks automaticamente. Depois, dás essas masks diretamente à tua U-Net como dados de treino de ground-truth.
Fazer o bootstrap de uma IA não exige trabalho humano se souberes como combinar a lógica de terreno do processamento de imagem clássico com arquiteturas de modelos modernas. Encorajo-te a explorar a documentação oficial do scikit-image e a tentar construir um mapa de elevação hands-on, e se tiveres uma ideia para a nossa próxima série, passa por devstories.eu e diz-me. É tudo por este episódio. Obrigado por ouvires, e continua a construir!
Tap to start playing
Browsers block autoplay
Share this episode
Episode
—
Copy this episode in another language:
Este site não utiliza cookies. O nosso fornecedor de alojamento pode registar o seu endereço de IP para efeitos analíticos. Saber mais.