zoukankan      html  css  js  c++  java
  • C#马赛克

     说到马赛克,一些闷骚男都懂的,“有马”、“无马”,此马即马赛克简称,可别光往邪恶的一面想,马赛克也有和谐的一面,比如一些新闻之类的将关键不想展示给观众的给和谐掉,此即马赛克应用。

        先看一张具有极低解析度的马赛克图案:

    看到一块块的同颜色块、或许你就能猜出其算法了。

    马赛克算法很简单,说白了就是把一张图片分割成若干个val * val像素的小区块(可能在边缘有零星的小块,但不影响整体算法,val越大,马赛克效果越明显),每个小区块的颜色都是相同的。为了方便起见,我们不妨让这个颜色就用该区域最左上角的那个点的颜色。当然还可以有其他方法,比如取区块中间点的颜色,或区块中随机点的颜色作代表等等。

    下面的示意图就是取val=2的结果。

    原图像素
    ABCDEFG
    HIJKLMN    
    OPQRSTU    
    VWXYZ01    
    2345678    

    马赛克处理后
    AACCEEG
    AACCEEG
    OOQQSSU
    OOQQSSU
    2244668

    原理就是那么简单。具体实现就看各人的思维习惯了。我的想法是:

    当y(当前高度)是val的整数倍时:
     扫描当前行中的每一点x,如果x也是val的整数倍,记录下当前x,y的颜色值;如果x不是val的整数倍,则沿用最近一次被记录的颜色值。
    当y不是val的整数倍:
     很简单,直接复制上一行。

    因此,区块越大,处理效果越明显;也可得出,源图片(R)对处理后的图片(S)是多对一映射,也就是说:马赛克处理后的图片是不可逆的,不要试图用可逆算法复原。

    /// <summary>
    /// 马赛克
    /// 是把一张图片分割成若干个N * N像素的小区块(可能在边缘有零星的小块,但不影响整体算法)
    /// ,每个小区块的颜色都是相同的。
    /// </summary>
    public class MosaicImage:IImageProcessable
    {
    #region IImageProcessable 成员

    public void ProcessBitmap(Bitmap bmp)
    {
    int width = bmp.Width;
    int height = bmp.Height;
    const int N = 5;//效果粒度,值越大码越严重
    int r = 0, g = 0, b = 0;
    Color c;
    for (int y = 0; y < height; y++)
    {
    for (int x = 0; x < width; x++)
    {

    if (y % N == 0)
    {
    if (x % N == 0)//整数倍时,取像素赋值
    {
    c = bmp.GetPixel(x, y);
    r = c.R;
    g = c.G;
    b = c.B;
    }
    else
    {
    bmp.SetPixel(x, y, Color.FromArgb(r, g, b));
    }
    }
    else //复制上一行
    {
    Color colorPreLine = bmp.GetPixel(x, y - 1);
    bmp.SetPixel(x, y, colorPreLine);

    }
    }
    }
    }

    public unsafe void UnsafeProcessBitmap(Bitmap bmp)
    {
    int width = bmp.Width;
    int height = bmp.Height;
    const int N = 5;//效果粒度,值越大码越严重
    int r = 0, g = 0, b = 0;
    Rectangle rect = new Rectangle(0, 0, width, height);
    BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
    byte* ptr = (byte*)(bmpData.Scan0);
    for (int y = 0; y < height; y++)
    {
    for (int x = 0; x < width; x++)
    {
    if (y % N == 0)
    {
    if (x % N == 0)
    {
    r = ptr[2];
    g = ptr[1];
    b = ptr[0];
    }
    else
    {
    ptr[2] = (byte)r;
    ptr[1] = (byte)g;
    ptr[0] = (byte)b;
    }
    }
    else //复制上一行
    {
    ptr[0] = ptr[0 - bmpData.Stride];//b;
    ptr[1] = ptr[1 - bmpData.Stride];//g;
    ptr[2] = ptr[2 - bmpData.Stride];//r
    }
    ptr += 4;
    }
    ptr += bmpData.Stride - width * 4;
    }
    bmp.UnlockBits(bmpData);

    }

    #endregion
    }

    下面分别是区块大小为5和9的处理效果:

  • 相关阅读:
    Python中的模块与包
    Mac eclipse找不到source的解决办法
    Git常用命令
    MiniCrowler
    九度题库(所有题目整理,适合计算机考研和面试的人用)
    gtest 安装
    计算广告的相关学习资源
    使用python pylab库 画线
    3到6年的.NETer应该掌握哪些知识?
    迭代器模式的一种应用场景以及C#对于迭代器的内置支持
  • 原文地址:https://www.cnblogs.com/wichell/p/2419953.html
Copyright © 2011-2022 走看看