PC SOFT

GRUPOS DE DISCUSSÃO PROFISSIONAL
WINDEVWEBDEV e WINDEV Mobile

Inicio → WINDEV 25 → Classe para processamento forense de imagens com correção de  //            Motion Blur (desfoque de movimento)
Classe para processamento forense de imagens com correção de // Motion Blur (desfoque de movimento)
Iniciado por Boller, nov., 04 2025 3:57 PM - Sem resposta
Membro registado
4.604 mensagems
Publicado em novembro, 04 2025 - 3:57 PM
Vou criar uma classe OOP WLanguage completa para processamento forense de imagens com Motion Deblur, baseada no procedimento que você descreveu:

```wlanguage
//==============================================================================
// Classe: CMotionDeblur
// Descrição: Classe para processamento forense de imagens com correção de
// Motion Blur (desfoque de movimento)
// Autor: Sistema
// Data: 04/11/2025
//==============================================================================

CMotionDeblur is Class

//--------------------------------------------------------------------------
// DECLARAÇÃO DE MEMBROS PRIVADOS
//--------------------------------------------------------------------------
PRIVATE
m_sImagemOriginal is string // Caminho da imagem original
m_imgProcessada is Image // Objeto Image para processamento
m_nLarguraOriginal is int // Largura original
m_nAlturaOriginal is int // Altura original
m_rFatorEsticamento is real = 1.0 // Fator de alongamento detectado
m_nAnguloBorrão is int = 0 // Ângulo do motion blur
m_nDeslocamento is int = 0 // Deslocamento do blur em pixels
m_rSNR is real = 100.0 // Signal-to-Noise Ratio
m_bImagemCarregada is boolean = False
m_sUltimoErro is string = ""
END

//--------------------------------------------------------------------------
// DECLARAÇÃO DE MEMBROS PÚBLICOS
//--------------------------------------------------------------------------
PUBLIC
// Propriedades de leitura
PROPERTY LarguraImagem, read = m_nLarguraOriginal
PROPERTY AlturaImagem, read = m_nAlturaOriginal
PROPERTY FatorEsticamento, read = m_rFatorEsticamento
PROPERTY AnguloBlur, read = m_nAnguloBorrão
PROPERTY Deslocamento, read = m_nDeslocamento
PROPERTY UltimoErro, read = m_sUltimoErro
PROPERTY ImagemCarregada, read = m_bImagemCarregada
END

END

//==============================================================================
// CONSTRUTOR
//==============================================================================
PROCEDURE Constructor()
m_bImagemCarregada = False
m_sUltimoErro = ""
END

//==============================================================================
// DESTRUTOR
//==============================================================================
PROCEDURE Destructor()
// Libera recursos se necessário
IF m_bImagemCarregada THEN
m_imgProcessada = Null
END
END

//==============================================================================
// Método: CarregarImagem
// Descrição: Carrega a imagem inicial para processamento
// Parâmetros:
// - sCaminhoImagem: Caminho completo da imagem
// Retorno: True se sucesso, False caso contrário
//==============================================================================
PROCEDURE PUBLIC CarregarImagem(LOCAL sCaminhoImagem is string): boolean

// Valida parâmetros
IF sCaminhoImagem = "" THEN
m_sUltimoErro = "Caminho da imagem não informado"
RESULT False
END

IF NOT fFileExist(sCaminhoImagem) THEN
m_sUltimoErro = StringBuild("Arquivo não encontrado: %1", sCaminhoImagem)
RESULT False
END

// Carrega a imagem
m_imgProcessada = dLoadImage(sCaminhoImagem)

IF m_imgProcessada..Width = 0 OR m_imgProcessada..Height = 0 THEN
m_sUltimoErro = "Falha ao carregar a imagem. Formato inválido?"
m_bImagemCarregada = False
RESULT False
END

// Armazena informações
m_sImagemOriginal = sCaminhoImagem
m_nLarguraOriginal = m_imgProcessada..Width
m_nAlturaOriginal = m_imgProcessada..Height
m_bImagemCarregada = True
m_sUltimoErro = ""

RESULT True

END

//==============================================================================
// Método: MedirEsticamento
// Descrição: Calcula o fator de esticamento medindo um objeto circular
// Parâmetros:
// - nDiametroX: Diâmetro horizontal medido (em pixels)
// - nDiametroY: Diâmetro vertical medido (em pixels)
// Retorno: Fator de esticamento calculado
//==============================================================================
PROCEDURE PUBLIC MedirEsticamento(LOCAL nDiametroX is int, LOCAL nDiametroY is int): real

LOCAL rFator is real

IF nDiametroX <= 0 OR nDiametroY <= 0 THEN
m_sUltimoErro = "Diâmetros inválidos para cálculo"
RESULT 1.0
END

// Calcula a razão entre os diâmetros
rFator = nDiametroX / nDiametroY

m_rFatorEsticamento = rFator

RESULT rFator

END

//==============================================================================
// Método: CorrigirEsticamento
// Descrição: Corrige o esticamento da imagem aplicando escala
// Parâmetros:
// - bDirecaoHorizontal: True para corrigir horizontalmente, False para vertical
// Retorno: True se sucesso, False caso contrário
//==============================================================================
PROCEDURE PUBLIC CorrigirEsticamento(LOCAL bDirecaoHorizontal is boolean = True): boolean

LOCAL nNovaLargura, nNovaAltura is int
LOCAL rFatorCorrecao is real

IF NOT m_bImagemCarregada THEN
m_sUltimoErro = "Nenhuma imagem carregada"
RESULT False
END

IF m_rFatorEsticamento = 1.0 THEN
// Sem esticamento detectado
RESULT True
END

// Calcula o fator de correção (inverso do esticamento)
rFatorCorrecao = 1.0 / m_rFatorEsticamento

// Aplica a correção na direção apropriada
IF bDirecaoHorizontal THEN
// Corrige horizontalmente
nNovaLargura = Round(m_nLarguraOriginal * rFatorCorrecao, 0)
nNovaAltura = m_nAlturaOriginal
ELSE
// Corrige verticalmente
nNovaLargura = m_nLarguraOriginal
nNovaAltura = Round(m_nAlturaOriginal * rFatorCorrecao, 0)
END

// Redimensiona a imagem
dResize(m_imgProcessada, nNovaLargura, nNovaAltura, drHomothetic)

// Atualiza dimensões
m_nLarguraOriginal = nNovaLargura
m_nAlturaOriginal = nNovaAltura

RESULT True

END

//==============================================================================
// Método: MedirLinhaBlur
// Descrição: Mede a linha do blur para determinar ângulo e deslocamento
// Parâmetros:
// - nX1, nY1: Ponto inicial da linha
// - nX2, nY2: Ponto final da linha
// Retorno: True se sucesso
//==============================================================================
PROCEDURE PUBLIC MedirLinhaBlur(LOCAL nX1 is int, LOCAL nY1 is int, LOCAL nX2 is int, LOCAL nY2 is int): boolean

LOCAL rDistancia is real
LOCAL rAngulo is real

IF NOT m_bImagemCarregada THEN
m_sUltimoErro = "Nenhuma imagem carregada"
RESULT False
END

// Calcula a distância (deslocamento do blur)
rDistancia = SquareRoot((nX2 - nX1)^2 + (nY2 - nY1)^2)
m_nDeslocamento = Round(rDistancia, 0)

// Calcula o ângulo em graus
IF nX2 = nX1 THEN
// Linha vertical
m_nAnguloBorrão = 90
ELSE
rAngulo = ATan((nY2 - nY1) / (nX2 - nX1))
m_nAnguloBorrão = Round(rAngulo * 180 / PI, 0)
END

RESULT True

END

//==============================================================================
// Método: AplicarMotionDeblur
// Descrição: Aplica o algoritmo de Motion Deblur
// Parâmetros:
// - nDeslocamento: Deslocamento do blur em pixels (opcional, usa medição se 0)
// - nAngulo: Ângulo do blur em graus (opcional, usa medição se 0)
// - rSNR: Signal-to-Noise Ratio (padrão: 100.0)
// Retorno: True se sucesso
//==============================================================================
PROCEDURE PUBLIC AplicarMotionDeblur(LOCAL nDeslocamento is int = 0, LOCAL nAngulo is int = 0, LOCAL rSNR is real = 100.0): boolean

LOCAL imgTemp is Image
LOCAL nShift, nAngle is int

IF NOT m_bImagemCarregada THEN
m_sUltimoErro = "Nenhuma imagem carregada"
RESULT False
END

// Usa valores medidos se não fornecidos
nShift = nDeslocamento
IF nShift = 0 THEN nShift = m_nDeslocamento

nAngle = nAngulo
IF nAngle = 0 THEN nAngle = m_nAnguloBorrão

IF nShift = 0 THEN
m_sUltimoErro = "Deslocamento não medido. Use MedirLinhaBlur primeiro."
RESULT False
END

m_rSNR = rSNR

// NOTA: WLanguage não possui função nativa de Motion Deblur
// Esta é uma implementação simplificada usando filtros disponíveis

// Aplica sharpen (nitidez) como aproximação
imgTemp = dCopy(m_imgProcessada)

// Filtro de nitidez baseado no deslocamento
LOCAL nIntensidade is int = Min(nShift * 2, 100)

dSharpen(imgTemp, nIntensidade)

// Aplica rotação se necessário (baseado no ângulo)
IF nAngle <> 0 THEN
dRotation(imgTemp, -nAngle, drNoEnlarging)
END

m_imgProcessada = imgTemp

RESULT True

END

//==============================================================================
// Método: AjustarBrilhoContraste
// Descrição: Ajusta brilho e contraste da imagem
// Parâmetros:
// - nBrilho: Ajuste de brilho (-100 a +100, 0 = sem alteração)
// - nContraste: Ajuste de contraste (-100 a +100, 0 = sem alteração)
// Retorno: True se sucesso
//==============================================================================
PROCEDURE PUBLIC AjustarBrilhoContraste(LOCAL nBrilho is int = 0, LOCAL nContraste is int = 50): boolean

IF NOT m_bImagemCarregada THEN
m_sUltimoErro = "Nenhuma imagem carregada"
RESULT False
END

// Valida parâmetros
nBrilho = Max(-100, Min(100, nBrilho))
nContraste = Max(-100, Min(100, nContraste))

// Ajusta brilho
IF nBrilho <> 0 THEN
dModifyLuminosity(m_imgProcessada, nBrilho)
END

// Ajusta contraste
IF nContraste <> 0 THEN
dModifyContrast(m_imgProcessada, nContraste)
END

RESULT True

END

//==============================================================================
// Método: RecortarArea
// Descrição: Recorta uma área específica da imagem (crop)
// Parâmetros:
// - nX, nY: Coordenadas do canto superior esquerdo
// - nLargura, nAltura: Dimensões da área a recortar
// Retorno: True se sucesso
//==============================================================================
PROCEDURE PUBLIC RecortarArea(LOCAL nX is int, LOCAL nY is int, LOCAL nLargura is int, LOCAL nAltura is int): boolean

LOCAL imgRecortada is Image

IF NOT m_bImagemCarregada THEN
m_sUltimoErro = "Nenhuma imagem carregada"
RESULT False
END

// Valida coordenadas
IF nX < 0 OR nY < 0 OR nLargura <= 0 OR nAltura <= 0 THEN
m_sUltimoErro = "Coordenadas de recorte inválidas"
RESULT False
END

IF nX + nLargura > m_imgProcessada..Width OR nY + nAltura > m_imgProcessada..Height THEN
m_sUltimoErro = "Área de recorte excede os limites da imagem"
RESULT False
END

// Cria nova imagem com a área recortada
imgRecortada..Width = nLargura
imgRecortada..Height = nAltura

dStartDrawing(imgRecortada)
dCopyImage(m_imgProcessada, imgRecortada, copySrcCopy, nX, nY, nLargura, nAltura, 0, 0)
dEndDrawing(imgRecortada)

m_imgProcessada = imgRecortada
m_nLarguraOriginal = nLargura
m_nAlturaOriginal = nAltura

RESULT True

END

//==============================================================================
// Método: ProcessamentoCompleto
// Descrição: Executa o fluxo completo de processamento forense
// Parâmetros:
// - stParametros: Estrutura com todos os parâmetros necessários
// Retorno: True se sucesso
//==============================================================================
PROCEDURE PUBLIC ProcessamentoCompleto(LOCAL stParametros is STParametrosDeblur): boolean

IF NOT m_bImagemCarregada THEN
m_sUltimoErro = "Nenhuma imagem carregada"
RESULT False
END

// 1. Correção de esticamento (se necessário)
IF stParametros.bCorrigirEsticamento THEN
IF NOT CorrigirEsticamento(stParametros.bDirecaoHorizontal) THEN
RESULT False
END
END

// 2. Aplicar Motion Deblur
IF NOT AplicarMotionDeblur(stParametros.nDeslocamento, stParametros.nAngulo, stParametros.rSNR) THEN
RESULT False
END

// 3. Ajustar Brilho e Contraste
IF NOT AjustarBrilhoContraste(stParametros.nBrilho, stParametros.nContraste) THEN
RESULT False
END

// 4. Recortar área (se especificado)
IF stParametros.bRecortar THEN
IF NOT RecortarArea(stParametros.nRecorteX, stParametros.nRecorteY, ...
stParametros.nRecorteLargura, stParametros.nRecorteAltura) THEN
RESULT False
END
END

RESULT True

END

//==============================================================================
// Método: SalvarImagem
// Descrição: Salva a imagem processada
// Parâmetros:
// - sCaminhoDestino: Caminho onde salvar a imagem
// - nQualidade: Qualidade da imagem (1-100, padrão: 95)
// Retorno: True se sucesso
//==============================================================================
PROCEDURE PUBLIC SalvarImagem(LOCAL sCaminhoDestino is string, LOCAL nQualidade is int = 95): boolean

IF NOT m_bImagemCarregada THEN
m_sUltimoErro = "Nenhuma imagem carregada"
RESULT False
END

IF sCaminhoDestino = "" THEN
m_sUltimoErro = "Caminho de destino não informado"
RESULT False
END

// Valida qualidade
nQualidade = Max(1, Min(100, nQualidade))

// Salva a imagem
IF NOT dSaveImageJPEG(m_imgProcessada, sCaminhoDestino, nQualidade) THEN
m_sUltimoErro = StringBuild("Erro ao salvar imagem: %1", ErrorInfo())
RESULT False
END

m_sUltimoErro = ""
RESULT True

END

//==============================================================================
// Método: ObterImagem
// Descrição: Retorna o objeto Image processado
// Retorno: Objeto Image
//==============================================================================
PROCEDURE PUBLIC ObterImagem(): Image

RESULT m_imgProcessada

END

//==============================================================================
// Método: ExibirEmControle
// Descrição: Exibe a imagem processada em um controle Image
// Parâmetros:
// - ctrlImagem: Controle Image onde exibir
// Retorno: True se sucesso
//==============================================================================
PROCEDURE PUBLIC ExibirEmControle(ctrlImagem is Control): boolean

IF NOT m_bImagemCarregada THEN
m_sUltimoErro = "Nenhuma imagem carregada"
RESULT False
END

IF ctrlImagem..Type <> typImage THEN
m_sUltimoErro = "Controle informado não é do tipo Image"
RESULT False
END

ctrlImagem = m_imgProcessada

RESULT True

END

//==============================================================================
// ESTRUTURA DE PARÂMETROS
//==============================================================================
STParametrosDeblur is Structure
// Correção de esticamento
bCorrigirEsticamento is boolean = False
bDirecaoHorizontal is boolean = True

// Motion Deblur
nDeslocamento is int = 0
nAngulo is int = 0
rSNR is real = 100.0

// Ajustes de imagem
nBrilho is int = 0
nContraste is int = 50

// Recorte
bRecortar is boolean = False
nRecorteX is int = 0
nRecorteY is int = 0
nRecorteLargura is int = 0
nRecorteAltura is int = 0
END
```

**Exemplo de uso da classe:**

```wlanguage
//==============================================================================
// EXEMPLO DE USO - Processamento Forense de Placa de Carro
//==============================================================================

PROCEDURE ExemploProcessamentoForense()

LOCAL objDeblur is CMotionDeblur
LOCAL stParams is STParametrosDeblur

// Cria instância da classe
objDeblur = new CMotionDeblur()

// Carrega imagem do carro com placa borrada
IF NOT objDeblur.CarregarImagem("C:\Fotos\carro_borrado.jpg") THEN
Error("Erro ao carregar imagem: " + objDeblur.UltimoErro)
RETURN
END

Info(StringBuild("Imagem carregada: %1 x %2 pixels", ...
objDeblur.LarguraImagem, objDeblur.AlturaImagem))

// Mede a linha do blur na placa
// Exemplo: linha traçada do ponto (320, 245) até (380, 250)
objDeblur.MedirLinhaBlur(320, 245, 380, 250)

Info(StringBuild("Blur medido: %1 pixels, ângulo: %2°", ...
objDeblur.Deslocamento, objDeblur.AnguloBlur))

// Configura parâmetros para processamento completo
stParams.bCorrigirEsticamento = False // Sem esticamento neste caso
stParams.nDeslocamento = 0 // Usa medição automática
stParams.nAngulo = 0 // Usa medição automática
stParams.rSNR = 100.0
stParams.nBrilho = -20 // Escurece fundo
stParams.nContraste = 70 // Aumenta contraste
stParams.bRecortar = True
stParams.nRecorteX = 300
stParams.nRecorteY = 230
stParams.nRecorteLargura = 120
stParams.nRecorteAltura = 40

// Executa processamento completo
IF NOT objDeblur.ProcessamentoCompleto(stParams) THEN
Error("Erro no processamento: " + objDeblur.UltimoErro)
RETURN
END

// Exibe resultado em controle de imagem
objDeblur.ExibirEmControle(IMG_Resultado)

// Salva imagem processada
IF objDeblur.SalvarImagem("C:\Fotos\placa_nitida.jpg", 95) THEN
Info("Imagem processada salva com sucesso!")
ELSE
Error("Erro ao salvar: " + objDeblur.UltimoErro)
END

// Libera objeto
delete objDeblur

END

//==============================================================================
// EXEMPLO 2 - Processamento Manual Passo a Passo
//==============================================================================

PROCEDURE ExemploProcessamentoManual()

LOCAL objDeblur is CMotionDeblur

objDeblur = new CMotionDeblur()

// 1. Carrega imagem
IF NOT objDeblur.CarregarImagem("C:\Fotos\placa_borrada.jpg") THEN
Error(objDeblur.UltimoErro)
RETURN
END

// 2. Mede esticamento (se objeto circular visível)
// Exemplo: diâmetro horizontal = 150px, vertical = 100px
LOCAL rFator is real = objDeblur.MedirEsticamento(150, 100)
Info("Fator de esticamento: " + rFator)

// 3. Corrige esticamento
objDeblur.CorrigirEsticamento(True) // Corrige horizontalmente

// 4. Mede linha do blur
objDeblur.MedirLinhaBlur(100, 50, 150, 55)

// 5. Aplica deblur
objDeblur.AplicarMotionDeblur() // Usa medições automáticas

// 6. Ajusta brilho e contraste
objDeblur.AjustarBrilhoContraste(-15, 60)

// 7. Recorta área de interesse
objDeblur.RecortarArea(80, 40, 100, 30)

// 8. Exibe e salva
objDeblur.ExibirEmControle(IMG_Processada)
objDeblur.SalvarImagem("C:\Fotos\resultado_final.jpg")

delete objDeblur

END
```

**Características da classe:**

1. **Encapsulamento completo** - Todos os membros privados com propriedades de leitura
1. **Tratamento de erros** - Propriedade `UltimoErro` para diagnóstico
1. **Fluxo completo ou manual** - Método `ProcessamentoCompleto()` ou métodos individuais
1. **Validações rigorosas** - Todos os parâmetros são validados
1. **Compatibilidade WX** - Usa funções nativas: `dLoadImage`, `dSharpen`, `dModifyLuminosity`, etc.
1. **Estrutura de parâmetros** - `STParametrosDeblur` para configuração organizada

**Limitações técnicas:**

O WLanguage **não possui** implementação nativa de algoritmos complexos como Motion Deblur (Wiener deconvolution). A classe usa **aproximações** com filtros disponíveis (`dSharpen`, `dRotation`). Para resultados profissionais similares ao ImageJ, seria necessário integrar com DLLs externas ou usar APIs de processamento de imagem.


Mas nada impede usar python e outras linguagens como complementar para atingir esse objetivo.

--
Adriano José Boller
______________________________________________
Consultor e Representante Oficial da
PcSoft no Brasil
+55 (41) 99949 1800
adrianoboller@gmail.com
skype: adrianoboller
http://wxinformatica.com.br/