Mostrando postagens com marcador algoritmo. Mostrar todas as postagens
Mostrando postagens com marcador algoritmo. Mostrar todas as postagens

sexta-feira, 8 de dezembro de 2017

Project - Euler 4

O enunciado do problema de nº 4 pede que se encontre o maior palíndromo da multiplicação de 2 números de 3 dígitos.


O enfoque aqui será o de implementar a solução tendo por base o método de busca de palíndromos que utilizamos no post Invertendo String e Palíndromos. Também, utilizaremos o fato de que estamos a procura do maior palíndromo, logo faz mais sentido começarmos a busca pelos números mais altos, dividindo a busca em intervalos [999-900], [899-700], etc. Assim sendo, quando encontrarmos um palíndromo, certamente será o maior, pois estamos multiplicando números maiores do que os intervalos que se seguirão. A busca então pode ser interrompida, acelerando a resposta.

Function ehPalindromo($pal) {
    $reversePal = -join([System.Linq.Enumerable]::Reverse($pal))
    if ($pal -eq $reversePal) {
        Return $true
    }
    else {
        Return $false
    }
}

Function VerPalNoIntervalo([Int32]$int1, [Int32]$int2) {
    [Int32]$max = 0
    For ($i=$int1; $i -gt $int2; $i--) {
        For ($j=$int1; $j -gt $int2; $j--) {
            If (ehPalindromo ([String]($i*$j))) {
                If (($i * $j) -gt $max) {
                    $max = $i * $j
                    Write-Host "Palíndromo entre $i * $j = $max"
                    Return $max
                }
            }
        } ## for $j
    } ## for $i
    Return 0
}

Clear-Host
[Int32]$i=999
For ([Int32]$j=899; $j -gt 100; $j-=100) {
    $i = $j + 100
    If (VerPalNoIntervalo $i $j) {
        Write-Host "O maior palíndromo encontrado de 3 dígitos foi: $max"
        Break
    }
}


Na implementação, a função ehPalindromo retorna $true se o número em questão é palíndromo. A função VerPalNoIntervalo recebe um intervalo, por exemplo [999-900], e verifica se há um palíndromo nesse intervalo - a verificação é feita chamando a função ehPalindromo.
No corpo principal, foi construído um loop que chama a função VerPalNoIntervalo passando os intervalos de busca. Conforme dito, como a busca está sendo feita a partir dos números maiores, em bloco, ao ser encontrado um palíndromo é seguro deduzir que é o maior.

Palíndromo entre 993 * 913 = 906609
O maior palíndromo encontrado de 3 dígitos foi: 906609

segunda-feira, 4 de dezembro de 2017

Project Euler 2

Implementaremos 2 soluções para o problema de nº 2 do Project Euler:


Estamos implementando uma solução através do uso de recursividade (RecursiveFibonacciEvenSum) e outra utilizando um loop (FibonacciEvenSum).

Function RecursiveFibonacciEvenSum([Long]$pre, [Long]$cur, [Long]$evenSum) {
    If ($cur -gt 4000000) { Return $evenSum}
    If ($cur %2 -eq 0) { $evenSum = $evenSum + $cur }
    [Long]$tmp = $pre + $cur
    $pre = $cur
    $cur = $tmp
    RecursiveFibonacciEvenSum $pre $cur $evenSum
}
 
Function FibonacciEvenSum([Long]$pre, [Long]$cur) {
    [Long]$tmp = 0
    [Long]$evenSum = 0
 
    While($tmp -lt 4000000) {
        $tmp = $pre + $cur
        If ($tmp % 2 -eq 0) { $evenSum = $evenSum + $tmp }
        $pre = $cur
        $cur = $tmp
    }
    Return $evenSum
}
 
Clear-Host
$time = New-Object System.Diagnostics.Stopwatch
$time.Start()
RecursiveFibonacciEvenSum 1 1 0
$time.Stop()
$ts = $time.Elapsed
Write-Host "Tempo calculado com Recursividade:"
Write-Host $ts.Seconds "segundos e" $ts.Milliseconds "milisegundos"
 
$time2 = New-Object System.Diagnostics.Stopwatch
$time2.Start()
FibonacciEvenSum 1 1
$time2.Stop()
$ts2 = $time2.Elapsed
Write-Host "Tempo calculado com Loop:"
Write-Host $ts2.Seconds "segundos e" $ts2.Milliseconds "milisegundos"

Calculamos a soma dos números pares na Série de Fibonacci, obtendo 4613732 como resultado. Com relação ao tempo gasto, observamos que a implementação através de loop teve melhor desempenho do que a solução que utiliza recursividade.

4613732
Tempo calculado com Recursividade:
0 segundos e 157 milisegundos

4613732
Tempo calculado com Loop:
0 segundos e 28 milisegundos

quarta-feira, 22 de novembro de 2017

Detectando Cores

Aqui vamos supor que se deseja converter uma imagem colorida em escala (tons) de cinza, tal qual fizemos anteriormente em Convertendo Imagens para Preto e Branco, em Halftone Floyd-Steinberg e em Halftone Floyd-Steinberg - Falso e Verdadeiro, mas desejamos manter os tons de uma determinada cor na imagem.

Para que seja definido quais cores (tonalidades) serão convertidas para tons de cinza e quais permanecerão na tonalidade escolhida, leva-se em conta um pouco de subjetividade, mas também é preciso calcular a "distância" entre a cor que vamos usar como referência para que sejam mantidos os tons e a cor da imagem original, estipulando uma tolerância (um limiar), pois dependendo da abrangência mínima ou máxima poderão ser atingidas tonalidades próximas a outras cores e essas serão (ou não) afetadas também no processo da conversão, ou seja, cores não desejadas podem ser mantidas coloridas ao invés de convertidas em tons de cinza.

O mais comum para estabelecer a "distância" ou "diferença" entre 2 cores R1G1B1 e R2G2B2 é o uso da fórmula Euclidiana:


Tentando estabelecer uma fórmula que gere tons com maior afinidade com a percepção do olho humano, uma das propostas é o uso de pesos na fórmula Euclidana:


Uma proposta alternativa (CompuPhase) é a de levar em consideração, na fórmula de pesos Euclidiana, o quanto de vermelho há em um determinado tom de cor. Primeiro, calcula-se o nível médio de vermelho entre as cores e depois os deltas RGB entre as cores como função desse nível médio. Ainda persiste a questão subjetiva da escolha da cor de referência a ser comparada com cada tom na imagem, mas os resultados são aceitáveis e com bom desempenho.


Uma possível implementação segue abaixo, onde a função FSbutRGB recebe os parâmetros $Img (imagem colorida), $cor (cor de referência) e $tolerancia (se a diferença das cores for menor que a tolerância, mantém a cor original).
Function FSbutRGB([System.Drawing.Image]$Img, [System.Drawing.Color]$cor, [Int32]$tolerancia) {
    Write-Host -ForegroundColor Green "Convertendo para escala de cinza, com tolerância: $tolerancia"
    Write-Host -ForegroundColor DarkYellow "Será mantida na imagem tons da cor:"$cor.Name
    Write-Host -ForegroundColor Green "Será salvo na mesma pasta um arquivo NomeOriginal_FSbutRGB.jpg"
    [Int32]$p=0
    Foreach($y in (0..($Img.Height-1))) {
        $p++
        If ($p -gt (($Img.Height)*0.05)) { 
            Write-Host -NoNewLine '.'
            $p = 0
        }
        Foreach($x in (0..($Img.Width-1))) {
            $ColorPixel = $Img.GetPixel($x,$y)
            ## Algoritmo Color Metric
            ## https://www.compuphase.com/cmetric.htm
            $rMed = (($ColorPixel.R)+$cor.R)/2
            $deltaR = (($ColorPixel.R)-$cor.R)
            $deltaG = (($ColorPixel.G)-$cor.G)
            $deltaB = (($ColorPixel.B)-$cor.B)
            $deltaC = [math]::Sqrt((2+$rMed/256)*$deltaR*$deltaR+4*$deltaG*$deltaG+(2+(255-$rMed)/256)*$deltaB*$deltaB)
            If ($deltaC -le $tolerancia) {
                $R = $ColorPixel.R
                $G = $ColorPixel.G
                $B = $ColorPixel.B
            }
            Else {
                $R = (0.2125*$ColorPixel.R)+(0.7154*$ColorPixel.G)+(0.0721*$ColorPixel.B)
                $G = $R
                $B = $R
            }
            $A = $ColorPixel.A
            $Img.SetPixel($x,$y,[System.Drawing.Color]::FromArgb([Int32]$A,[Int32]$R,[Int32]$G,[Int32]$B))
        } ## $x
    } ## $y
} ## EndFunction FSbutRGB

$Arquivo = New-Object System.Windows.Forms.OpenFileDialog
$Arquivo.filter = "Imagens (*.PNG;*.BMP;*.JPG;*.JPEG;*.GIF)|*.PNG;*.BMP;*.JPG;*.JPEG;*.GIF"
$Arquivo.ShowDialog() | Out-Null
$ArquivoSemExt = ($Arquivo.filename).Substring(0,($Arquivo.filename).Length-4)
$Img = [System.Drawing.Image]::FromFile($Arquivo.filename)

Clear-Host
Write-Host "##############################################"
Write-Host "Arquivo de Imagem:"$Arquivo.filename
Write-Host "##############################################"

FSbutRGB $Img '0x00007F' 100

Write-Host ""
Write-Host -ForegroundColor Yellow "Conversão concluída!"
$Img.Save($ArquivoSemExt+"_FSbutRGB.jpg","JPEG")
$Img.Dispose()


Supondo a seguinte imagem colorida:


No código-exemplo, estamos convertendo essa imagem para tons (escala) de cinza, e gostaríamos de manter a cor de referência cujo valor hexa é 0x00007F, com uma tolerância de valor 100. O resultado é o seguinte:


Utilizando para a cor de referência um valor hexa de 0x004401, mantendo-se a mesma tolerância.


Agora para "pegar" a cor vermelha, através de uma cor de referência, em hexa, 0xB40608 foi preciso ajustar a tolerância para 150.


O caso da cor amarela é mais interessante de ser observado, pois há 3 tons de amarelo na imagem. Um deles próximo à cor verde, outro próximo a cor vermelha e, finalmente, o tom de amarelo que decidimos manter, com uma cor hexa de referência 0xF7D600.

Primeiro experimento com uma tolerância de valor 150, produz o seguinte:


Segundo experimento com uma tolerância de valor 100, produz o seguinte:

No terceiro experimento encontramos um valor de tolerância que atinge o objetivo (70):

sexta-feira, 17 de novembro de 2017

Séries de Taylor - Cosseno

Neste post, vamos implementar o cálculo do cosseno de um ângulo através de um série de Taylor.

Function Fatorial([Int32]$num) {
    if ($num -eq 0) { return 1 }
    return $num * (Fatorial($num-1))
}

Function Cosseno($x,$max) {
    $CossenoX = 1 - ([math]::Pow($x,2) / (Fatorial 2))
    For ($n=2;$n -lt $max;$n++) {
        $CossenoX = $CossenoX + [math]::Pow(-1,$n)*[math]::Pow($x,(2*$n)) / (Fatorial (2*$n))
    }
    Return $CossenoX 
}

Clear-Host
$angulo = Read-Host "Digite um ângulo para calcular o Cosseno"
$rad = $angulo / 180 * [math]::PI
$Cosseno = [math]::Round((Cosseno $rad 20),10)
Write-Host -ForeGroundColor Yellow "Cos($angulo°)=$Cosseno"

terça-feira, 14 de novembro de 2017

Séries de Taylor - Seno

Aqui um exercício de implementação de um algoritmo para o cálculo do Seno de um ângulo através de uma série de Taylor.

Na implementação, estamos fixando as iterações em 20 e o arredondamento em 10 casas decimais. Observa-se a função de apoio Fatorial, a mesma que implementamos no post sobre recursividade.
Function Fatorial([Int32]$num) {
    if ($num -eq 0) { return 1 }
    return $num * (Fatorial($num-1))
}

Function Seno($x,$max) {
    $senoX = $x - ([math]::Pow($x,3) / (Fatorial 3))
    For ($n=2;$n -lt $max;$n++) {
        $senoX = $senoX + [math]::Pow(-1,$n)*[math]::Pow($x,(2*$n+1)) / (Fatorial (2*$n+1))
    }
    Return $senoX 
}

Clear-Host
$angulo = Read-Host "Digite um ângulo para calcular o Seno"
$rad = $angulo / 180 * [math]::PI
$seno = [math]::Round((Seno $rad 20),10)
Write-Host -ForeGroundColor Yellow "Seno($angulo°)=$seno"

segunda-feira, 13 de novembro de 2017

Halftone Floyd-Steinberg - Falso e Verdadeiro

A implementação de Floyd-Steinberg conforme proposta no post anterior é na verdade considerada como False Floyd-Steinberg. Neste post, vamos propor uma melhoria, refatoração, daquele código, mas também uma implementação mais fidedigna do Floyd-Steinberg ao final. Como dito, o código do post anterior poderia ser melhorado, principalmente em sua parte inicial, na conversão para tons de cinza e na descoberta dos valores máximos e mínimos de branco e preto, que era feita em 2 etapas, pode ser feito em 1 etapa. Ainda, como a conversão para tons de cinza gera valores RGB iguais, não há necessidade de recálculo, basta calcular um deles.

Eis o código melhorado.
Function FloydSteinberg([System.Drawing.Image]$Img) {
    Write-Host -ForegroundColor Green "Aplicando efeito FloydSteinberg na imagem..."
    Write-Host -ForegroundColor Green "Será salvo na mesma pasta um arquivo NomeOriginal_FloydSteinberg.jpg"
    ## Primeiro converte a imagem para tons de cinza
    Write-Host "Convertendo para tons de cinza e calculando min/max de B/W"
    [Int32]$BLACK = 255
    [Int32]$WHITE = 0
    Foreach($y in (0..($Img.Height-1))) {
        Foreach($x in (0..($Img.Width-1))) {
            $ColorPixel = $Img.GetPixel($x,$y)
            $R = (0.2125*$ColorPixel.R)+(0.7154*$ColorPixel.G)+(0.0721*$ColorPixel.B)
            $G = $R
            $B = $R
            $A = $ColorPixel.A
            $Img.SetPixel($x,$y,[System.Drawing.Color]::FromArgb([Int32]$A,[Int32]$R,[Int32]$G,[Int32]$B))
            If ($R -lt $BLACK) { $BLACK = $R}
            If ($R -gt $WHITE) { $WHITE = $R}
        }
    }

    Write-Host "WHITE:$WHITE"
    Write-Host "BLACK:$BLACK"
    [Int32]$T = ($BLACK + $WHITE) / 2
    Write-Host "Aplicando Efeito FloydSteinberg..."
    [Int32]$p=0
    [Int32]$Err
    Foreach($y in (0..($Img.Height-1))) {
        $p++
        If ($p -gt (($Img.Height)*0.05)) { 
            Write-Host -NoNewLine '.'
            $p = 0
        }
        Foreach($x in (0..($Img.Width-1))) {
            $ColorPixel = $Img.GetPixel($x,$y)
            ## FloydSteinberg
            If ($ColorPixel.R -lt $T) {
                $R = $BLACK
                $G = $BLACK
                $B = $BLACK
                $Err = $ColorPixel.R - $BLACK
            }
            Else {
                $R = $WHITE
                $G = $WHITE
                $B = $WHITE
                $Err = $ColorPixel.R - $WHITE
            }
            ## SetPixel para efeito FloydSteinberg
            $A = $ColorPixel.A
            $Img.SetPixel($x,$y,[System.Drawing.Color]::FromArgb([Int32]$A,[Int32]$R,[Int32]$G,[Int32]$B))

            If (($x+1) -lt ($Img.Width-1)) {
                $CPx1 = $Img.GetPixel(($x+1),$y)
                $Ax1 = $CPx1.A
                $Rx1 = $CPx1.R + 3 * $Err / 8
                $Gx1 = $CPx1.G + 3 * $Err / 8
                $Bx1 = $CPx1.B + 3 * $Err / 8
                If ($Rx1 -lt 0) { $Rx1 = 0}
                If ($Gx1 -lt 0) { $Gx1 = 0}
                If ($Bx1 -lt 0) { $Bx1 = 0}
                If ($Rx1 -gt 255) { $Rx1 = 255}
                If ($Gx1 -gt 255) { $Gx1 = 255}
                If ($Bx1 -gt 255) { $Bx1 = 255}
                $Img.SetPixel(($x+1),$y,[System.Drawing.Color]::FromArgb([Int32]$Ax1,[Int32]$Rx1,[Int32]$Gx1,[Int32]$Bx1))
            }

            If (($y+1) -lt ($Img.Height-1)) {
                $CPy1 = $Img.GetPixel($x,($y+1))
                $Ay1 = $CPy1.A
                $Ry1 = $CPy1.R + 3 * $Err / 8
                $Gy1 = $CPy1.G + 3 * $Err / 8
                $By1 = $CPy1.B + 3 * $Err / 8
                If ($Ry1 -lt 0) { $Ry1 = 0}
                If ($Gy1 -lt 0) { $Gy1 = 0}
                If ($By1 -lt 0) { $By1 = 0}
                If ($Ry1 -gt 255) { $Ry1 = 255}
                If ($Gy1 -gt 255) { $Gy1 = 255}
                If ($By1 -gt 255) { $By1 = 255}
                $Img.SetPixel($x,($y+1),[System.Drawing.Color]::FromArgb([Int32]$Ay1,[Int32]$Ry1,[Int32]$Gy1,[Int32]$By1))
            }
            If ((($y+1) -lt ($Img.Height-1)) -And (($x+1) -lt ($Img.Width-1))) {
                $CPx1y1 = $Img.GetPixel(($x+1),($y+1))
                $Ax1y1 = $CPx1y1.A
                $Rx1y1 = $CPx1y1.R + $Err / 4
                $Gx1y1 = $CPx1y1.G + $Err / 4
                $Bx1y1 = $CPx1y1.B + $Err / 4
                If ($Rx1y1 -lt 0) { $Rx1y1 = 0}
                If ($Gx1y1 -lt 0) { $Gx1y1 = 0}
                If ($Bx1y1 -lt 0) { $Bx1y1 = 0}
                If ($Rx1y1 -gt 255) { $Rx1y1 = 255}
                If ($Gx1y1 -gt 255) { $Gx1y1 = 255}
                If ($Bx1y1 -gt 255) { $Bx1y1 = 255}
                $Img.SetPixel(($x+1),($y+1),[System.Drawing.Color]::FromArgb([Int32]$Ax1y1,[Int32]$Rx1y1,[Int32]$Gx1y1,[Int32]$Bx1y1))
            }
        } ## ForEach $x
    } ## ForEach $y
} ## EndFunction FloydSteinberg

$Arquivo = New-Object System.Windows.Forms.OpenFileDialog
$Arquivo.filter = "Imagens (*.PNG;*.BMP;*.JPG;*.JPEG;*.GIF)|*.PNG;*.BMP;*.JPG;*.JPEG;*.GIF"
$Arquivo.ShowDialog() | Out-Null
$ArquivoSemExt = ($Arquivo.filename).Substring(0,($Arquivo.filename).Length-4)
$Img = [System.Drawing.Image]::FromFile($Arquivo.filename)

Clear-Host
Write-Host "##############################################"
Write-Host "Arquivo de Imagem:"$Arquivo.filename
Write-Host "##############################################"

FloydSteinberg $Img

Write-Host ""
Write-Host -ForegroundColor Yellow "Conversão concluída!"
$Img.Save($ArquivoSemExt+"_FloydSteinberg.jpg","JPEG")
$Img.Dispose()


IMAGEM COLORIDA


EFEITO FALSE FLOYD-STEINBERG


Floyd-Steinberg Verdadeiro
Function FloydSteinberg([System.Drawing.Image]$Img) {
    Write-Host -ForegroundColor Green "Aplicando efeito FloydSteinberg na imagem..."
    Write-Host -ForegroundColor Green "Será salvo na mesma pasta um arquivo NomeOriginal_FloydSteinberg.jpg"
    ## Primeiro converte a imagem para tons de cinza
    Write-Host "Convertendo para tons de cinza e calculando min/max de B/W"
    [Int32]$BLACK = 255
    [Int32]$WHITE = 0
    Foreach($y in (0..($Img.Height-1))) {
        Foreach($x in (0..($Img.Width-1))) {
            $ColorPixel = $Img.GetPixel($x,$y)
            $R = (0.2125*$ColorPixel.R)+(0.7154*$ColorPixel.G)+(0.0721*$ColorPixel.B)
            $G = $R
            $B = $R
            $A = $ColorPixel.A
            $Img.SetPixel($x,$y,[System.Drawing.Color]::FromArgb([Int32]$A,[Int32]$R,[Int32]$G,[Int32]$B))
            If ($ColorPixel.R -lt $BLACK) { $BLACK = $ColorPixel.R}
            If ($ColorPixel.R -gt $WHITE) { $WHITE = $ColorPixel.R}
        }
    }
    Write-Host "WHITE:$WHITE"
    Write-Host "BLACK:$BLACK"
    [Int32]$T = ($BLACK + $WHITE) / 2
    Write-Host "Aplicando Efeito FloydSteinberg..."
    [Int32]$p=0
    [Int32]$quant_error=0
    Foreach($y in (0..($Img.Height-1))) {
        $p++
        If ($p -gt (($Img.Height)*0.05)) { 
            Write-Host -NoNewLine '.'
            $p = 0
        }
        Foreach($x in (0..($Img.Width-1))) {
            $ColorPixel = $Img.GetPixel($x,$y)
            ## FloydSteinberg
            If ($ColorPixel.R -lt $T) {
                $R = $BLACK
                $G = $BLACK
                $B = $BLACK
                $quant_error = $ColorPixel.R - $BLACK
            }
            Else {
                $R = $WHITE
                $G = $WHITE
                $B = $WHITE
                $quant_error = $ColorPixel.R - $WHITE
            }
            $A = $ColorPixel.A
            $Img.SetPixel($x,$y,[System.Drawing.Color]::FromArgb([Int32]$A,[Int32]$R,[Int32]$G,[Int32]$B))
            ## SetPixels FloydSteinberg (x+1,y)
            If (($x+1) -lt ($Img.Width-1)) {
                $CPx1 = $Img.GetPixel(($x+1),$y)
                $Ax1 = $CPx1.A
                $Rx1 = $CPx1.R + $quant_error * 7 / 16
                $Gx1 = $CPx1.G + $quant_error * 7 / 16
                $Bx1 = $CPx1.B + $quant_error * 7 / 16
                If ($Rx1 -lt 0) { $Rx1 = 0}
                If ($Gx1 -lt 0) { $Gx1 = 0}
                If ($Bx1 -lt 0) { $Bx1 = 0}
                If ($Rx1 -gt 255) { $Rx1 = 255}
                If ($Gx1 -gt 255) { $Gx1 = 255}
                If ($Bx1 -gt 255) { $Bx1 = 255}
                $Img.SetPixel(($x+1),$y,[System.Drawing.Color]::FromArgb([Int32]$Ax1,[Int32]$Rx1,[Int32]$Gx1,[Int32]$Bx1))
            }
            ## SetPixels FloydSteinberg (x-1,y+1)
            If ( (($y+1) -lt ($Img.Height-1)) -And (($x-1) -gt 0) ) {
                $CPx1y1 = $Img.GetPixel(($x-1),($y+1))
                $Ax1y1 = $CPx1y1.A
                $Rx1y1 = $CPx1y1.R + $quant_error * 3 / 16
                $Gx1y1 = $CPx1y1.G + $quant_error * 3 / 16
                $Bx1y1 = $CPx1y1.B + $quant_error * 3 / 16
                If ($Rx1y1 -lt 0) { $Rx1y1 = 0}
                If ($Gx1y1 -lt 0) { $Gx1y1 = 0}
                If ($Bx1y1 -lt 0) { $Bx1y1 = 0}
                If ($Rx1y1 -gt 255) { $Rx1y1 = 255}
                If ($Gx1y1 -gt 255) { $Gx1y1 = 255}
                If ($Bx1y1 -gt 255) { $Bx1y1 = 255}
                $Img.SetPixel(($x-1),($y+1),[System.Drawing.Color]::FromArgb([Int32]$Ax1y1,[Int32]$Rx1y1,[Int32]$Gx1y1,[Int32]$Bx1y1))
            }
            ## SetPixels FloydSteinberg (x,y+1)
            If (($y+1) -lt ($Img.Height-1)) {
                $CPy1 = $Img.GetPixel($x,($y+1))
                $Ay1 = $CPy1.A
                $Ry1 = $CPy1.R + $quant_error * 5 / 16
                $Gy1 = $CPy1.G + $quant_error * 5 / 16
                $By1 = $CPy1.B + $quant_error * 5 / 16
                If ($Ry1 -lt 0) { $Ry1 = 0}
                If ($Gy1 -lt 0) { $Gy1 = 0}
                If ($By1 -lt 0) { $By1 = 0}
                If ($Ry1 -gt 255) { $Ry1 = 255}
                If ($Gy1 -gt 255) { $Gy1 = 255}
                If ($By1 -gt 255) { $By1 = 255}
                $Img.SetPixel($x,($y+1),[System.Drawing.Color]::FromArgb([Int32]$Ay1,[Int32]$Ry1,[Int32]$Gy1,[Int32]$By1))
            }
            ## SetPixels FloydSteinberg (x+1,y+1)
            If ((($y+1) -lt ($Img.Height-1)) -And (($x+1) -lt ($Img.Width-1))) {
                $CPx1y1 = $Img.GetPixel(($x+1),($y+1))
                $Ax1y1 = $CPx1y1.A
                $Rx1y1 = $CPx1y1.R + $quant_error * 1 / 16
                $Gx1y1 = $CPx1y1.G + $quant_error * 1 / 16
                $Bx1y1 = $CPx1y1.B + $quant_error * 1 / 16
                If ($Rx1y1 -lt 0) { $Rx1y1 = 0}
                If ($Gx1y1 -lt 0) { $Gx1y1 = 0}
                If ($Bx1y1 -lt 0) { $Bx1y1 = 0}
                If ($Rx1y1 -gt 255) { $Rx1y1 = 255}
                If ($Gx1y1 -gt 255) { $Gx1y1 = 255}
                If ($Bx1y1 -gt 255) { $Bx1y1 = 255}
                $Img.SetPixel(($x+1),($y+1),[System.Drawing.Color]::FromArgb([Int32]$Ax1y1,[Int32]$Rx1y1,[Int32]$Gx1y1,[Int32]$Bx1y1))
            }
        } ## ForEach $x
    } ## ForEach $y
} ## EndFunction FloydSteinberg

$Arquivo = New-Object System.Windows.Forms.OpenFileDialog
$Arquivo.filter = "Imagens (*.PNG;*.BMP;*.JPG;*.JPEG;*.GIF)|*.PNG;*.BMP;*.JPG;*.JPEG;*.GIF"
$Arquivo.ShowDialog() | Out-Null
$ArquivoSemExt = ($Arquivo.filename).Substring(0,($Arquivo.filename).Length-4)
$Img = [System.Drawing.Image]::FromFile($Arquivo.filename)

Clear-Host
Write-Host "##############################################"
Write-Host "Arquivo de Imagem:"$Arquivo.filename
Write-Host "##############################################"

FloydSteinberg $Img

Write-Host ""
Write-Host -ForegroundColor Yellow "Conversão concluída!"
$Img.Save($ArquivoSemExt+"_FloydSteinberg.jpg","JPEG")
$Img.Dispose()

Abaixo comparativo entre o falso e o verdadeiro Floyd-Steinberg

EFEITO FALSE FLOYD-STEINBERG


EFEITO TRUE FLOYD-STEINBERG