Académique Documents
Professionnel Documents
Culture Documents
Despus de explicar en que consisten, presentaremos el cdigo de la clase gImage en la que se han definido varios mtodos para que el usuario pueda procesarlas mediante un programa genrico que permite subir imgenes a un servidor Web.
375
Una imagen es una codificacin en un dominio espacial bidimensional esttico y esto nos permite que podamos contar con nuevas imgenes a partir de las originales sin tener que modificarlas haciendo uso de transformaciones o filtros aplicados a sus pixeles. Si consideramos una imagen con resolucin de 512 x 384 pixeles, su almacenamiento sin compresin ser en 590 Kbytes y otra de 2592 x 1728 pixeles estar almacenada en 13.4 Mbytes. Con tcnicas de compresin, esta ultima puede almacenarse en un archivo de 2.9 Mbytes. Para las transformaciones y filtros que aplicaremos estaremos tratando con las imgenes, con esos espacios bidimensionales, que difieren mucho de los diferentes formatos de archivos en que las podemos almacenar en un disco duro por ejemplo. Para acceder a los datos de una imagen Bitmap a continuacin presentamos la clase BitmapData que utilizaremos un poco ms adelante en diferentes aplicaciones en el procesamiento digital de imgenes.
376
Textos Universitarios / Serie Docencia ________________________________________________________________________ Especifica los atributos de una imagen de mapa de bits. La clase BitmapData la utilizan los mtodos LockBits y UnlockBits de la clase Bitmap. No puede heredarse.
PixelFormat
Reserved Scan0
Stride
Width
377
Jenaro C. Paz ________________________________________________________________________ Reemplazado. Permite que un objeto Object intente liberar recursos y realizar otras operaciones de limpieza antes de que el objeto Object sea reclamado por el recolector de elementos no utilizados. En C# y C++, los finalizadores se expresan mediante la sintaxis del destructor. MemberwiseClone (se hereda de Object) Crea una copia superficial del objeto Object actual. Finalize (se hereda de Object)
El objetivo en la deteccin de orillas es determinar las orillas de las formas en una imagen y ser capaz de dibujar un bitmap resultante donde las orillas estn en blanco sobre un fondo negro. La idea es muy sencilla, nos desplazamos por la imagen pixel por pixel comparando el color de cada uno con su vecino de la derecha y de abajo. Si alguna de estas comparaciones resulta en una diferencia muy grande el pixel estudiado es parte de una orilla y debe ponerse en blanco, de otra manera se pone en negro. Para llevar a cabo la comparacin de colores entre pixeles lo haremos mediante apuntadores, ya que .Net no cuenta con un mtodo que permita acceder a los datos de un pxel en forma directa.
Refirindonos a la figura anterior, BitmapData es la clase que mediante sus mtodos Stride y Scan0 nos permitir acceder a la informacin de la imagen en cuestin.
378
A continuacin se presenta la Clase gImage que iremos agrandando con nuevos mtodos segn vayamos avanzando en los diferentes temas asociados con el procesamiento digital de imgenes. El primer mtodo que se ha incluido es EdgeDetect que se utiliza para la deteccin de orillas. Para entender el funcionamiento del mismo se hace uso de las figuras 8.2 y 8.3, donde se inicia haciendo un recorrido por todos los bytes de la imagen rengln por rengln y columna por columna. Tenga en cuenta que cada vez que termina un rengln hay que avanzar nOffset bytes para acceder al siguiente y as sucesivamente.
gImage.cs
namespace JCPGraphics { /// <summary> /// Summary description for gImage. /// </summary> public class gImage { public gImage() { // // TODO: Add constructor logic here // } public static Bitmap EdgeDetect(Bitmap curImage, byte nThreshold)
379
|-------------pixeles----------------|--nOffset--|
int nPixel1 = 0, nPixel2 = 0; for(int y=0;y<curImage.Height-1;y++) { for(int x=0; x < nWidth-3; x++ ) { cRed=Math.Pow(Math.Abs(p2[0]-(p2+3)[0]),2); cGreen=Math.Pow(Math.Abs(p2[1]-(p2+3)[1]),2); cBlue=Math.Pow(Math.Abs(p2[2]-(p2+3)[2]),2); nPixel1=(int)Math.Sqrt(cRed+cGreen+cBlue); cRed=Math.Pow(Math.Abs(p2[0]-(p2+stride)[0]),2); cGreen=Math.Pow(Math.Abs(p2[1]-(p2+stride)[1]),2); cBlue=Math.Pow(Math.Abs(p2[2]-(p2+stride)[2]),2); nPixel2=(int)Math.Sqrt(cRed+cGreen+cBlue); if ((nPixel1>=nThreshold)|| (nPixel2 >= nThreshold)) nPixel1 = 255; else nPixel1 = 0; p[0] = p[1]=p[2]=(byte) nPixel1; p++; p2++; } p +=nOffset; p2 +=nOffset; } } curImage.UnlockBits(bmData); bClone.UnlockBits(bmDataC);
380
Para hacer uso de esta biblioteca implementamos una forma Web como la siguiente:
Figura 8.4. Forma Web para subir una imagen al servidor IIS
Que nos permitir hacer la bsqueda de una imagen en la computadora del usuario y luego subirla al servidor Web.
UploadEdgeDetection.aspx
<%@ Page language="c#" Codebehind="UploadEdgeDetection.aspx.cs" AutoEventWireup="false" Inherits="JCPGraphics.UploadEdgeDetection" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <HTML> <HEAD> <title>WebForm1</title> <meta content="Microsoft Visual Studio .NET 7.1" name="GENERATOR"> <meta content="C#" name="CODE_LANGUAGE"> <meta content="JavaScript" name="vs_defaultClientScript"> <meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema"> </HEAD> <body MS_POSITIONING="GridLayout"> <form id="Form1" action="/?scid=UploadFile.aspx&fp=1" method="post" encType="multipart/form-data" runat="server"> <asp:label id="Label2" style="Z-INDEX: 108; LEFT: 24px; POSITION: absolute; TOP: 16px" runat="server" Font-Size="Large" Width="592px" Font-Bold="True" ForeColor="Blue">Jpg and Png File Process (Edge Detection) </asp:label>
381
UploadEdgeDetection.aspx.cs
using using using using System; System.Collections; System.ComponentModel; System.Data;
382
namespace JCPGraphics { /// <summary> /// Summary description for WebForm1. /// </summary> public class UploadEdgeDetection : System.Web.UI.Page { public static string strFileName; public static string strFilePath; public static string newStrFilePath; public static string strFolder; public static string mimeType; public static string fileExt; protected System.Web.UI.WebControls.Button btnUpload; protected System.Web.UI.WebControls.Label lblUploadResult; protected System.Web.UI.WebControls.Label Label1; protected System.Web.UI.WebControls.Image Image1; protected System.Web.UI.WebControls.Button btnProcess; protected System.Web.UI.WebControls.Image Image2; protected System.Web.UI.WebControls.Label Label2; protected System.Web.UI.WebControls.Label Label3; protected System.Web.UI.WebControls.Label Label4; protected System.Web.UI.WebControls.Label Label5; protected System.Web.UI.WebControls.TextBox txtWidth; protected System.Web.UI.WebControls.TextBox txtHeight; protected System.Web.UI.WebControls.Label Label6; protected System.Web.UI.HtmlControls.HtmlGenericControl Header; protected System.Web.UI.HtmlControls.HtmlInputFile oFile; private void Page_Load(object sender, System.EventArgs e) { if(!IsPostBack) { File.Delete ("C:/TEMP/Image01.JPG"); File.Delete ("C:/TEMP/Image02.JPG"); File.Delete ("C:/TEMP/Image01.PNG"); File.Delete ("C:/TEMP/Image02.PNG"); } } #region Web Form Designer generated code override protected void OnInit(EventArgs e) { // // CODEGEN: This call is required by the ASP.NET Web Form Designer.
383
384
private void btnProcess_Click(object sender, System.EventArgs e) { btnProcess.Visible =false; int w1= UInt16.Parse(txtWidth.Text ); int h1= UInt16.Parse(txtHeight.Text ); Bitmap uploadImage =new Bitmap(newStrFilePath); //////////////////////////////////////////////////////////////// uploadImage=gImage.EdgeDetect1(uploadImage,50); /////////////////////////////////////////////////////////////// if (mimeType=="image/pjpeg" ) { newStrFilePath=strFolder+"Image02.jpg"; uploadImage.Save(newStrFilePath,ImageFormat.Jpeg); } if (mimeType=="image/x-png" ) { newStrFilePath=strFolder+"Image02.png"; uploadImage.Save(newStrFilePath,ImageFormat.Png); } Image2.ImageUrl=newStrFilePath; Image2.Visible=true; Image1.Visible=false;
385
Una vez que el usuario selecciona una imagen de su computadora, sta es enviada al servidor y al accionar el botn para procesarla se obtiene un resultado como el mostrado a continuacin.
386
Entonces:
El mayor valor que puede tomar esta expresin es 255 3 y como debemos cuidar que la magnitud de esta expresin nunca rebase 255 debemos normalizarla multiplicando por 1/ 3 As:
Es la proyeccin normalizada de un pxel en la direccin de los grises. Teniendo esto en mente, haremos un mtodo para recorrer todos los pixeles de una imagen para generar su componente gris. gImage.GrayscaleNormalized
public static Bitmap GrayScaleNormalized(Bitmap curImage) { BitmapData imgData = curImage.LockBits(new Rectangle(0, 0,curImage.Width, curImage.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); int stride = imgData.Stride; System.IntPtr Scan0 = imgData.Scan0; unsafe { byte * p = (byte *)(void *)Scan0; byte byteBlue, byteGreen, byteRed; int nOffset = stride - curImage.Width *3; int nHeight = curImage.Height; int nWidth= curImage.Width; for(int y = 0; y < nHeight; y++)
387
utilizamos
uploadImage=gImage.GrayscaleNormalized(uploadImage);
para procesar una imagen a color obtendremos una nueva imagen en gris como la mostrada a continuacin.
8.2.1.3 Inversin
El valor mas grande que puede tomar un color es 255 y el mas pequeo 0, entonces si deseamos invertir las contribuciones de los diferentes pixeles a la formacin de una
388
Textos Universitarios / Serie Docencia ________________________________________________________________________ imagen, debemos restar su color de 255 y esta diferencia tomarla como la contribucin al color de la nueva imagen. En la figura 8.8 se observa una grfica entre la seal de entrada y la de salida en el caso de la inversin.
Teniendo esto en mente, haremos un mtodo para recorrer todos los pixeles de una imagen y generaremos su correspondiente imagen invertida.
gImage.Invert
public static Bitmap Invert(Bitmap curImage) { BitmapData imgData = curImage.LockBits(new Rectangle(0,0,curImage.Width, curImage.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); int stride = imgData.Stride; System.IntPtr Scan0 = imgData.Scan0; unsafe { byte *p = (byte *)Scan0; int nHeight = curImage.Height; int nWidth= curImage.Width *3; int nOffset = stride - nWidth; for(int y = 0; y < nHeight; y++) { for (int x = 0; x < nWidth; x++) { p[0] = (byte)(255-p[0]); p++; } p+=nOffset; } }
389
utilizamos
uploadImage=gImage.Invert(uploadImage);
para procesar una imagen a color obtendremos una nueva imagen invertida como la mostrada a continuacin.
8.2.1.4 Brillo
Aumentar el brillo de una imagen consiste en sumar o restar una constante a los colores que constituyen un pxel, cuidando siempre de nunca rebasar los lmites 0 y 255. Si observamos la siguiente figura, aumentar o disminuir el brillo en una imagen consiste en aumentar o disminuir la ordenada al origen de la lnea recta con pendiente a 45 grados que representa los grises.
390
Teniendo esto en mente, haremos un mtodo para recorrer todos los pixeles de una imagen y generaremos su correspondiente imagen donde hemos aumentado o disminuido el brillo gImage.Brightness
public static Bitmap Brightness(Bitmap curImage, int nBrightness) { if (nBrightness < -255 ) nBrightness = -10; if (nBrightness > 255 ) nBrightness = 10; BitmapData imgData = curImage.LockBits(new Rectangle(0, 0, curImage.Width, curImage.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); int stride = imgData.Stride; System.IntPtr Scan0 = imgData.Scan0; int []Bright_transform = new int [256]; for(int i=0; i<256; i++) { Bright_transform[i] =i +nBrightness; if(Bright_transform[i] > 255) if(Bright_transform[i] < 0 ) } Bright_transform[i] =255; Bright_transform[i] =0;
unsafe { byte * p = (byte *)Scan0; int nOffset = stride - curImage.Width*3; int nWidth = curImage.Width * 3; int nHeight = curImage.Height; for(int y=0;y<nHeight;y++) { for(int x=0; x < nWidth; x++ )
391
utilizamos
uploadImage=gImage.Brightness(uploadImage,60);
para procesar una imagen a color obtendremos una nueva imagen con ms brillo como la mostrada a continuacin.
8.2.1.5 Contraste
Si observamos la siguiente figura, aumentar o disminuir el contraste en una imagen consiste en aumentar o disminuir la pendiente de la lnea recta con pendiente a 45 grados que representa los grises, cuidando siempre de nunca rebasar los lmites 0 y 255.
392
As, la frmula que tenemos que aplicar en este tipo de transformacin tiene la forma siguiente: Ntese que esta frmula representa una familia de rectas que pasan por el punto (128,128) con diferentes pendientes. Teniendo lo anterior en mente, haremos un mtodo para recorrer todos los pixeles de una imagen y generaremos su correspondiente imagen donde hemos aumentado o disminuido el contraste. gImage.Contrast
public static Bitmap Contrast(Bitmap curImage, double ContrastAngle) { double cvalue = 0; double contrast = Math.Tan(ContrastAngle*Math.PI/180.0); int nred, ngreen, nblue; int nWidth = curImage.Width; int nHeight = curImage.Height; BitmapData imgData = curImage.LockBits(new Rectangle(0, 0, nWidth, nHeight), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); int stride = imgData.Stride; System.IntPtr Scan0 = imgData.Scan0; unsafe { byte * p = (byte *)Scan0; int nOffset = stride - curImage.Width*3; for(int y=0;y<nHeight;++y)
393
utilizamos
uploadImage=gImage.Contrast(uploadImage,80);
para procesar una imagen a color obtendremos una nueva imagen donde el contraste se ha aumentado considerablemente.
394
gImage.ModifyColor
public static Bitmap ModifyColor(Bitmap curImage, int nred, int ngreen, int nblue) { if (nred < -255 || nred > 255) nred=0; if (ngreen < -255 || ngreen > 255) ngreen=0; if (nblue < -255 || nblue > 255) nblue=0; int nWidth = curImage.Width; int nHeight = curImage.Height; BitmapData imgData = curImage.LockBits(new Rectangle(0, 0, nWidth, nHeight), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); int stride = imgData.Stride; System.IntPtr Scan0 = imgData.Scan0; unsafe { byte * p = (byte *)Scan0; int nOffset = stride - curImage.Width*3; int nPixel; for(int y=0;y<nHeight;++y) { for(int x=0; x < nWidth; ++x ) { nPixel = p[2] + nred; nPixel = Math.Max(nPixel, 0); p[2] = (byte)Math.Min(255, nPixel); nPixel = p[1] + ngreen; nPixel = Math.Max(nPixel, 0); p[1] = (byte)Math.Min(255, nPixel); nPixel = p[0] + nblue; nPixel = Math.Max(nPixel, 0); p[0] = (byte)Math.Min(255, nPixel); p += 3; }
395
utilizamos
uploadImage=gImage.ModifyColor(uploadImage,10,-10,20);
para procesar una imagen a color obtendremos una nueva imagen donde hemos modificado los colores rojos en 10 unidades, los colores verdes en -10 unidades y los colores azules en 20 unidades.
396
Que al ser tabulada para diferentes valores de Gamma nos produce una grfica como la siguiente:
Si observamos esta grfica lo que podemos concluir es lo siguiente: Para gamma = 1 no hay ninguna correccin Para gamma > 1 hay una gran correccin en el contraste para valores pequeos del color de entrada mientras que una pequea correccin en el contraste para valores grandes. El brillo aumenta ms para valores intermedios del color de entrada. Para gamma < 1 hay una pequea correccin en el contraste para valores pequeos del color de entrada mientras que una gran correccin en el contraste para valores grandes. El brillo disminuye ms para valores intermedios del color de entrada.
Teniendo lo anterior en cuenta, haremos un mtodo para recorrer todos los pixeles de una imagen y generaremos su correspondiente imagen donde hemos aumentado o disminuido su gamma en cierta cantidad.
397
398
utilizamos
uploadImage=gImage.Gamma(uploadImage,1.2,0.8,1.4);
para procesar una imagen a color obtendremos una nueva imagen donde hemos modificado el coeficiente Gamma en los colores rojos en 1.2 unidades, en los colores verdes en 0.8 unidades y en los colores azules en 1.4 unidades.
O bien esta otra donde hemos modificado el coeficiente Gamma en los colores rojo verde y azul en 0.8 unidades.
399
A continuacin se presenta un mtodo para recorrer todos los pixeles de una imagen invirtiendolos verticalmente, hace uso de los mtodos GetPixel y SetPixel de la Clase Bitmap.
gImage.Flip
public static Bitmap Flip(Bitmap curImage) { Bitmap bTemp = (Bitmap)curImage.Clone(); curImage = new Bitmap (bTemp.Width, bTemp.Height, bTemp.PixelFormat ); int nWidth = bTemp.Width; int nHeight= bTemp.Height; for(int x=0; x < nWidth; x++) for(int y=0; y < nHeight; y++) { curImage.SetPixel(x,y,bTemp.GetPixel(x,nHeight-(y+1))); } return curImage; }
400
utilizamos
uploadImage=gImage.Flip(uploadImage);
para procesar una imagen a color obtendremos una nueva imagen donde la hemos invertido.
401
A continuacin se presenta un mtodo para recorrer todos los pixeles de una imagen invirtiendolos horizontalmente, tambin hace uso de los mtodos GetPixel y SetPixel de la Clase Bitmap.
gImage.Mirror
public static Bitmap Mirror(Bitmap curImage) { Bitmap bTemp = (Bitmap)curImage.Clone(); curImage = new Bitmap (bTemp.Width, bTemp.Height, bTemp.PixelFormat ); int nWidth = bTemp.Width; int nHeight= bTemp.Height; for(int x=0; x < nWidth; x++) for(int y=0; y < nHeight; y++) { curImage.SetPixel(x,y,bTemp.GetPixel(nWidth-(x+1),y)); } return curImage; }
utilizamos
uploadImage=gImage.Mirror(uploadImage);
para procesar una imagen a color obtendremos una nueva imagen espejo de la original 402
403
utilizamos
uploadImage=gImage.Scale(uploadImage,100,67,true);
para procesar una imagen a color obtendremos una nueva imagen reducida de la original
404
public static Bitmap Rotate(Bitmap curImage,int angle) { int newCanvasSize=(int)(Math.Sqrt(Math.Pow (curImage.Width,2.0)+Math.Pow(curImage.Height,2.0) )); Bitmap pixelImage = new Bitmap(newCanvasSize,newCanvasSize); Graphics g = Graphics.FromImage(pixelImage); g.Clear(System.Drawing.Color.White); rae z X = new rae z(); Rectangle toCenterImage = new Rectangle( (newCanvasSize-curImage.Width)/2, (newCanvasSize-curImage.Height)/2, curImage.Width , curImage.Height ); Point pCenterOfCanvas = new Point(newCanvasSize/2, newCanvasSize/2); X.RotateAt(angle,pCenterOfCanvas,MatrixOrder.Append); g.Transform=X; g.DrawImage(curImage,toCenterImage); return pixelImage; }
405
Jenaro C. Paz ________________________________________________________________________ Si en la forma Web que utilizamos en el ejercicio anterior en vez de
uploadImage=gImage.Scale(uploadImage,100,67, rae);
utilizamos
uploadImage=gImage.Rotate(uploadImage,30);
para procesar una imagen a color obtendremos una nueva imagen donde hemos girado la imagen original en 30 grados en sentido de las manecillas del reloj.
406
Aqu b1 es proporcional a un porcentaje del ancho de la imagen original y a1 es la mitad de b1. La relacin entre las Xs del rectngulo y las del trapecio esta dada por:
Y la relacin entre las Ys y Xs del rectngulo con las Ys del trapecio estn dadas por:
Y la relacin entre las Ys y Xs del rectngulo con las Ys del trapecio estn dadas por:
407
Para la parte inferior del trapecio. A continuacin se presenta un mtodo que hace uso de los algoritmos mencionados. gImage.PerspectiveX
public static Bitmap PerspectiveX(Bitmap curImage, float percentage, Color bgColor) { Bitmap bTemp = (Bitmap)curImage.Clone(); float b1 = (float)(Math.Abs(percentage*0.007*curImage.Width)) ; float a1 = b1/2; curImage = new Bitmap (curImage.Width, curImage.Height, bTemp.PixelFormat ); Graphics g = Graphics.FromImage(curImage); g.Clear(bgColor); int imWidth = curImage.Width ; int imHeight = curImage.Height; if(percentage >0) { for(int x=0;x<imWidth ; x++) { int x2 = (int)(x*(imWidth-b1)/imWidth); //upper half for(int y=0;y<imHeight/2 ; y++) { int y2 =(int)(y + a1*x2/(imWidth -b1)2*y*a1*x2/((imWidth -b1)*imHeight)); curImage.SetPixel(x2,y2,bTemp.GetPixel(x,y)); } //lower half for(int y=imHeight/2 ;y<imHeight; y++) { int y2 =(int)(y - a1*x2/(imWidth -b1)+ 2*(imHeighty)*a1*x2/((imWidth -b1)*imHeight)); curImage.SetPixel(x2,y2,bTemp.GetPixel(x,y)); } } } else { for(int x=0;x<imWidth ; x++) { int x2 = (int)(b1+x*(imWidth-b1)/imWidth); for(int y=0;y<imHeight/2 ; y++) { int y2 =(int)(y + a1*(imWidth-x2)/(imWidth -b1)2*y*a1*(imWidth-x2)/((imWidth -b1)*imHeight)); curImage.SetPixel(x2,y2,bTemp.GetPixel(x,y));
408
utilizamos
uploadImage=gImage.PerspectiveX(uploadImage,10,Color.White);
para procesar una imagen a color obtendremos una nueva imagen donde hemos realizado una perspectiva horizontal modificado la imagen original en 10 % .
409
Aqu b1 es proporcional a un porcentaje del ancho de la imagen original y a1 es el doble de b1. La relacin entre las Ys del rectngulo y las del trapecio esta dada por:
Y la relacin entre las Xs y Ys del rectngulo con las Xs del trapecio estn dadas por:
Cuando el porcentaje en la perspectiva es negativo, la relacin entre las Ys rectngulo y las del trapecio esta dada por:
del
Y la relacin entre las Xs y Ys del rectngulo con las Xs del trapecio estn dadas por:
410
Textos Universitarios / Serie Docencia ________________________________________________________________________ Para la parte izquierda de la imagen y por:
Para la parte derecha. A continuacin se presenta un mtodo que hace uso de los algoritmos mencionados.
gImage.PerspectiveY
public static Bitmap PerspectiveY(Bitmap curImage, Color icolor) { Bitmap bTemp = (Bitmap)curImage.Clone(); icol percentage,
icol b1 = ( icol)(Math.Abs(percentage*0.005*curImage.Width)) ; icol a1 = b1*2; curImage = new Bitmap (curImage.Width, curImage.Height, bTemp.PixelFormat ); Graphics g = Graphics.FromImage(curImage); g.SmoothingMode=SmoothingMode.HighQuality; g.Clear( icolor); int imWidth = curImage.Width ; int imHeight = curImage.Height; if(percentage >0) { for(int y=0;y<imHeight ; y++) { int y2 = (int)(y*(imHeight-a1)/imHeight); // Left Side for(int x=0;x<imWidth/2 ; x++) { int x2 =(int)(x + b1*y2/(imHeight a1)2*x*b1*y2/((imHeight a1)*imWidth)); curImage.SetPixel(x2,y2,bTemp.GetPixel(x,y)); } //Right Side for(int x=imWidth/2 ;x<imWidth; x++) { int x2 =(int)(x b1*y2/(imHeight a1)+ 2*(imWidthx)*b1*y2/((imHeight a1)*imWidth)); curImage.SetPixel(x2,y2,bTemp.GetPixel(x,y)); } } } else { for(int y=0;y<imHeight ; y++)
411
utilizamos
uploadImage=gImage.PerspectiveY(uploadImage,20,Color.White);
para procesar una imagen a color obtendremos una nueva imagen donde hemos realizado una perspectiva vertical modificado la imagen original en 20 % .
412
utilizamos
413
para procesar una imagen a color obtendremos una nueva imagen donde hemos realizado una inclinacin horizontal modificado la imagen original en un ngulo de 30 grados .
gImage.SkewVer
public static Bitmap SkewVer(Bitmap curImage, int angle) { int newCanvasHeight=(int)(curImage.Height +curImage.Width *
414
utilizamos
uploadImage=gImage.SkewVer(uploadImage,30);
para procesar una imagen a color obtendremos una nueva imagen donde hemos realizado una inclinacin vertical modificado la imagen original en un ngulo de 30 grados .
415
Los kernels pueden tener tamaos arbitrarios, pero los de 3 x 3 son los ms usados en la mayora de las situaciones (tambin debido a que son los mas rpidos), ya que solo toma en consideracin el valor del pixel mismo y el de sus 8 vecinos. Ahora, para aplicar este kernel a una imagen debe colocarse el kernel sobre la imagen y multiplicar los valores de color por 1 o 4. El resultado se suma y divide por 12, en este caso (la suma de los elementos del kernel). A continuacin se presenta una seccin de una imagen en grises, sobre la que se aplicar el kernel de convolucin.
La hemos escogido en grises para facilitar la explicacin, ahora bien sobre cada uno de los pixeles de esta seccin de imagen, colocamos el valor de su color, teniendo como entendido que por ejemplo 150 = (150, 150, 150) en sus componentes rojo, verde y azul.
416
Ahora colocamos el kernel sobre los pixeles de la imagen y el primer pixel que obtenemos es el (2,2), luego al desplazarnos con el kernel a la derecha el siguiente pixel que obtendremos ser el (2,3) y as sucesivamente.
Si se tratara de una imagen no de grises, esto mismo hay que hacer para cada una de las tres componentes (R, V, A) que constituyen al pixel, originando 9 multiplicaciones 8 sumas y una divisin por un factor de tres para cada uno de los pixeles de la imagen que se vayan a procesar. Por ejemplo si contamos con una imagen de 512 x 384 pixeles hay que realizar alrededor de 10. 5 millones de operaciones para obtener la imagen filtrada. Si nos fijamos bien, los pixeles de la orilla no pueden ser procesados porque no cuentan con todos sus vecinos para aplicar el algoritmo entonces se tienen que desechar.
A continuacin se presenta un mtodo que multiplica una imagen por una matriz de Convolucin de 3 x 3
417
418
Hay que tener en mente que para cada matriz de convolucin se tendr un filtrado diferente, es lo que veremos a continuacin.
419
gImage.GaussianBlur
public static Bitmap GaussianBlur(Bitmap curImage, int nWeight /* default to 4*/) { ConvMatrix conMat = new ConvMatrix(); conMat.initialize (1); conMat.elements[1,1] = nWeight; conMat.elements [0,1] = conMat.elements[1,0] = conMat.elements[1,2] = conMat.elements[2,1] = 2; conMat.Factor = nWeight + 12; return } gImage.DoConvolution3x3(curImage, conMat);
utilizamos
uploadImage=gImage.GaussianBlur(uploadImage,8);
para procesar una imagen a color obtendremos una nueva imagen donde hemos realizado un borrado Gaussiano modificado la imagen original usando un peso de 8 en la matriz de convolucin .
420
gImage.Emboss
public static Bitmap Emboss(Bitmap curImage) { ConvMatrix conMat = new ConvMatrix(); conMat.initialize(0); conMat.elements[0,0] = 2; conMat.elements[1,1] = conMat.elements[2,2] = -1;
utilizamos
uploadImage=gImage.Emboss(uploadImage);
para procesar una imagen a color, obtendremos una nueva imagen donde hemos realizado un realzado modificado la imagen original.
421
gImage.Sharpen
public static Bitmap Sharpen(Bitmap curImage, int nWeight { ConvMatrix conMat = new ConvMatrix(); conMat.initialize(0); conMat.elements[1,1] = nWeight; conMat.elements[0,1] = conMat.elements[1,0] = conMat.elements[1,2] = conMat.elements[2,1] = -1; conMat.Factor = nWeight - 4; return } gImage.DoConvolution3x3(curImage, conMat);
utilizamos
uploadImage=gImage.Sharpen(uploadImage,10);
para procesar una imagen a color, obtendremos una nueva imagen donde hemos realizado una modificacin a la imagen original por nitidez.
422
utilizamos
uploadImage=gImage.Smooth(uploadImage,4);
para procesar una imagen a color, obtendremos una nueva imagen donde hemos realizado una modificacin a la imagen original por suavizado.
423
public static Bitmap MeanRemoval(Bitmap curImage, int nWeight /* default to 9*/ ) { ConvMatrix conMat = new ConvMatrix(); conMat.initialize(-1); conMat.elements[1,1] = nWeight; conMat.Factor = nWeight - 8; return gImage.DoConvolution3x3(curImage, conMat); }
utilizamos
uploadImage=gImage.MeanRemoval(uploadImage,4);
para procesar una imagen a color, obtendremos una nueva imagen donde hemos realizado una modificacin a la imagen original por MeanRemoval.
424
public static Bitmap EdgeDetectionQuick(Bitmap curImage) { ConvMatrix conMat = new ConvMatrix(); conMat.elements[0,0] = conMat.elements[0,1] = conMat.elements[0,2] = -1; conMat.elements[1,0] = conMat.elements[1,1] = conMat.elements[1,2] = 0; conMat.elements[2,0] = conMat.elements[2,1] = conMat.elements[2,2] = 1; conMat.Offset = 127; return } gImage.DoConvolution3x3(curImage, conMat);
utilizamos
uploadImage=gImage.EdgeDetectionQuick(uploadImage,4);
para procesar una imagen a color, obtendremos una nueva imagen donde hemos realizado una modificacin a la imagen original por deteccion de orillas.
425
gImage.EdgeDetectionConvolution
public static Bitmap EdgeDetectionConvolution(Bitmap curImage, short nType, byte nThreshold) { ConvMatrix conMat = new ConvMatrix(); Bitmap bTemp = (Bitmap)curImage.Clone(); switch (nType) { case SOBEL_EDGE_DETECT: conMat.initialize(0); conMat.elements[0,0] = conMat.elements[0,2] = conMat.elements[1,0] = conMat.elements[1,2] = conMat.Offset = 0; break; case PREWITT_EDGE_DETECT: conMat.initialize(0); conMat.elements[0,0] = conMat.elements[2,0] = conMat.elements[0,2] = conMat.elements[2,2] = conMat.Offset = 0; break; case KIRSH_EDGE_DETECT: conMat.initialize(-3); conMat.elements[1,1] = conMat.elements[0,0] = conMat.elements[2,0] = conMat.Offset = 0; break; }
0; conMat.elements[1,0] = 5;
426
0; conMat.elements[0,1] = 5;
gImage.DoConvolution3x3(bTemp, conMat); // GDI+ still lies to us - the return format is BGR, NOT RGB. BitmapData bmData = curImage.LockBits(new Rectangle(0, 0, curImage.Width, curImage.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); BitmapData bmData2 = bTemp.LockBits(new Rectangle(0, 0, curImage.Width, curImage.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); int stride = bmData.Stride; System.IntPtr Scan0 = bmData.Scan0; System.IntPtr Scan02 = bmData2.Scan0; unsafe { byte * p = (byte *)(void *)Scan0; byte * p2 = (byte *)(void *)Scan02; int nOffset = stride - curImage.Width*3; int nWidth = curImage.Width * 3; int nPixel = 0; for(int y=0;y<curImage.Height;++y) { for(int x=0; x < nWidth; ++x )
427
utilizamos
uploadImage=gImage. EdgeDetectionConvolution(uploadImage, SOBEL_EDGE_DETECT, 200);
para procesar una imagen a color, obtendremos una nueva imagen donde hemos realizado una modificacin a la imagen original por deteccion de orillas Sobel.
utilizamos
uploadImage=gImage. EdgeDetectionConvolution(uploadImage, PREWITT_EDGE_DETECT, 200);
para procesar una imagen a color, obtendremos una nueva imagen donde hemos realizado una modificacin a la imagen original por deteccion de orillas Prewitt.
429
utilizamos
uploadImage=gImage. EdgeDetectionConvolution(uploadImage, KIRSH_EDGE_DETECT, 200);
para procesar una imagen a color, obtendremos una nueva imagen donde hemos realizado una modificacin a la imagen original por deteccion de orillas Prewitt.
430