Intuitivement en faisant un programme tres tres con avec un sobel de ce dont je me rapelle comment ca marche moi j’obtiens ca. C’est sur mes souvenir alors ca peut etre tres tres approximatif. Cela dit c’est un peu nawak de faire ca soi meme a la main
y a des outils de partout poru le faire je pense, mais bon ca m’interessait de comprendre comment ca marche donc voila…

En utilisant un sobel
|-1 0 1 |
|-2 0 2 |
|-1 0 1 |
pour dX et son symetrique pour dY. Sur des doubles avec le gradient normalise au fur et a mesure et remappe en RGB 0…255 de -1…+1 a la fin (avec un petit boost pour voir mieux). Surement pas la meilleure methode pour eviter minimiser les erreurs, mais les c’est plus smooth deja je pense. Ca laisse les artefacts cela dit comme toi… il est aussi possible qu’ils proviennent d’une compression en JPG ou quoi auparavant de l’image. On montre la « derivee » (le gradient) de l’image la, c’est trop le genre de truc ou une compression a perte va montrer son derriere, surtout vu l’espacement regulier des artifacts en question… m’enfin bon… ptet que ca a rien a voir, a creuser en essayant d’autre images ou une generee soi meme en soft…
Je mets l’essentiel du code a l’arrache en C# tout naze (mon code, pas C# :P) qui va a 2 a l’heure (on peut faire une section unsafe et multiplier les perfs par 1000 mais comme c’etait juste pour tester je peux faire marcher d’abord et me faire iech avec les pointeurs apres :P) :
[codebox]
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
namespace NormalizeMap
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private double ByteToDouble(byte a) {
return Convert.ToDouble(a) / 255.00;
}
private int DoubleToInt(double a)
{
return Convert.ToInt32(a * 255);
}
private void btnGo_Click(object sender, EventArgs e)
{
Bitmap bmp = this.pictureBox1.Image as Bitmap;
double[,] gradientX = new double[bmp.Width+1, bmp.Height+1];
double[,] gradientY = new double[bmp.Width+1, bmp.Height+1];
int[,] sobelY = new int[3, 3] { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } };
int[,] sobelX = new int[3, 3] { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 } };
Conv3x3(bmp, gradientX, sobelX);
Conv3x3(bmp, gradientY, sobelY);
Bitmap result = this.pictureBox1.Image.Clone() as Bitmap;
for (int y = 0; y < result.Height; y++)
{
for (int x = 0; x < result.Width; x++)
{
// 1. normalize dx, dy, 1
double[] vector = new double[3] { gradientX[x, y], gradientY[x, y], 1 };
Normalize(vector);
int[] RGB = new int[3] { DoubleToInt(vector[0]), DoubleToInt(vector[1]), DoubleToInt(vector[2]) };
MapTo0_255(RGB);
Color color = Color.FromArgb(RGB[0], RGB[1], RGB[2]);
result.SetPixel(x, y, color);
}
}
this.pictureBox2.Image = result;
}
private void MapTo0_255(int[] vector)
{
// clamp
vector[0] = Math.Max(-255, vector[0]);
vector[1] = Math.Max(-255, vector[1]);
vector[2] = Math.Max(-255, vector[2]);
vector[0] = Math.Min(255, vector[0]);
vector[1] = Math.Min(255, vector[1]);
vector[2] = Math.Min(255, vector[2]);
// remap
vector[0] = vector[0] / 2 + 128;
vector[1] = vector[1] / 2 + 128;
vector[2] = vector[2] / 2 + 128;
}
public void Normalize(double[] vector)
{
double norm = Math.Sqrt(vector[0] * vector[0] + vector[1] * vector[1] + vector[2] * vector[2]);
vector[0] = (vector[0] / norm);
vector[1] = (vector[1] / norm);
vector[2] = (vector[2] / norm);
}
public bool Conv3x3(Bitmap b, double[,] outputGradient, int[,] sobel)
{
for (int y = 1; y < b.Height - 1; y++)
{
for (int x = 1; x < b.Width - 1; x++)
{
outputGradient[x,y] = ByteToDouble(b.GetPixel(x-1,y-1).R) * sobel[0, 0] +
ByteToDouble(b.GetPixel(x , y - 1).R) * sobel[1, 0] +
ByteToDouble(b.GetPixel(x + 1, y - 1).R) * sobel[2, 0] +
ByteToDouble(b.GetPixel(x - 1, y).R) * sobel[0, 1] +
ByteToDouble(b.GetPixel(x , y ).R) * sobel[1, 1] +
ByteToDouble(b.GetPixel(x + 1, y ).R) * sobel[2, 1] +
ByteToDouble(b.GetPixel(x - 1, y + 1).R) * sobel[0, 2] +
ByteToDouble(b.GetPixel(x , y + 1).R) * sobel[1, 2] +
ByteToDouble(b.GetPixel(x + 1, y + 1).R) * sobel[2, 2];
outputGradient[x, y] *= 5; // SUPER BOOOST!!!!
}
}
return true;
}
}
}
[/codebox]
Le codebehind des fois que tu voudrais recompiler:
[codebox]
namespace NormalizeMap
{
partial class Form1
{
///
/// Required designer variable.
///
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.btnGo = new System.Windows.Forms.Button();
this.pictureBox2 = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.Image = global::NormalizeMap.Properties.Resources.badmap;
this.pictureBox1.Location = new System.Drawing.Point(12, 12);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(251, 254);
this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
//
// btnGo
//
this.btnGo.Location = new System.Drawing.Point(12, 272);
this.btnGo.Name = "btnGo";
this.btnGo.Size = new System.Drawing.Size(508, 23);
this.btnGo.TabIndex = 1;
this.btnGo.Text = "Go!";
this.btnGo.UseVisualStyleBackColor = true;
this.btnGo.Click += new System.EventHandler(this.btnGo_Click);
//
// pictureBox2
//
this.pictureBox2.Location = new System.Drawing.Point(269, 12);
this.pictureBox2.Name = "pictureBox2";
this.pictureBox2.Size = new System.Drawing.Size(251, 254);
this.pictureBox2.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.pictureBox2.TabIndex = 2;
this.pictureBox2.TabStop = false;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(527, 304);
this.Controls.Add(this.pictureBox2);
this.Controls.Add(this.btnGo);
this.Controls.Add(this.pictureBox1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.Button btnGo;
private System.Windows.Forms.PictureBox pictureBox2;
}
}
[/codebox]
Si j’ai fait plein d’erreurs ou si ca rame puissance 1000000 pas la peine de raler 