色子作画 Dice Mosaic

色子作画 Dice Mosaic

大概是一年前,公司的一个部门举办活动,他们想把请来的嘉宾的头像照片用色子拼出来,这个创意应该是来自http://my.tv.sohu.com/us/5721245/4911597.shtml,其实这件事可以用PS弄出来,但是比较费时间,所以花了一天时间给他们写了一个小程序。程序参考了这篇文章http://blog.jobbole.com/8563/

程序原理很简单,首先把图片转为一张灰度图,然后根据灰度图来判断用哪种类型的色子。

1.首先把图片转为灰度图

        /// <summary>
        /// 把原图像转化为灰度图,因为人眼对rgb三种颜色的敏感度不同,rgb的权值也不同
        /// </summary>
        /// <param name="rawBitmap"></param>
        /// <returns></returns>
        public Bitmap ConverttoGrayscale(Bitmap rawBitmap)
        {
            Bitmap grayBitmap = new Bitmap(rawBitmap.Width, rawBitmap.Height);
            for (int i = 0; i < rawBitmap.Width; i++)
            {
                for (int j = 0; j < rawBitmap.Height; j++)
                {
                    Color c = rawBitmap.GetPixel(i, j);
                    int grayValue = Convert.ToInt32(0.3 * c.R + 0.5 * c.G + 0.2 * c.B);
                    grayBitmap.SetPixel(i, j, Color.FromArgb(grayValue, grayValue, grayValue));
                }
            }
            return grayBitmap;
        }

2.根据灰度图来算出每个单元格的数值。
比如图片是800*800像素的,我有1600个色子,那么图片应该分成40*40的单元格,每个单元格用一个色子表示。换句话说,每个色子代表了20*20像素的面积。

        public Int32[,] ConverttoValue(Bitmap grayBitmap, int width, int height)
        {
            Int32[,] grayArray = new Int32[height, width];  //用于存储灰度的数据
            int gridSize = grayBitmap.Width / width;
            int average, total;
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    total = 0;
                    for (int m = 0; m < gridSize; m++)
                    {
                        for (int n = 0; n < gridSize; n++)
                        {
                            total += grayBitmap.GetPixel(j * gridSize + n, i * gridSize + m).R;
                            //这里用的是R,因为已经是灰度图了,所以每个像素的RGB值是相同的
                        }
                    }
                    average = total / gridSize / gridSize;   // 每个单元格灰度的平局值
                    grayArray[i, j] = average;
                }
            }
            return grayArray;
        }

3.根据灰度图中每个单元格的平局值,计算出对应哪种色子。

     //valueArray即第二步中计算出的数组
     //min,max即色子的最小和最大点数,一般我们用的色子最小是1最大是6
      public Int32[,] ConverttoNumber(Int32[,] valueArray, int min, int max)
        {
            Int32[,] numberArray = new Int32[valueArray.GetLength(0), valueArray.GetLength(1)];
            try
            {
                for (int i = 0; i < valueArray.GetLength(0); i++)
                {
                    for (int j = 0; j < valueArray.GetLength(1); j++)
                    {
                        int t = valueArray[i, j];
                        //numberArray[i, j] = t * (max - min ) / 255 + min;
                        numberArray[i, j] = (t == 255) ? max : t * (max - min + 1) / 255 + min;
                    }
                }
            }
            catch (Exception ex)
            { }

            return numberArray;
        }

4.知道所有单元格用哪种色子,就可以画图了。当然,这里还需要各种色子的图片。

public Bitmap DrawwithDice(Int32[,] numberArray)
{
     int gridSize = 30;
     //每个色子图片的大小。比如上文中800*800的图片,用40*40个色子,那么生成的图片大小为:40个*30像素即1200*1200像素。
     int row = numberArray.GetLength(0);
     int line = numberArray.GetLength(1);
     Bitmap bmpPaint = new Bitmap(line * gridSize + 90, row * gridSize + 90);
     Graphics gBoard = Graphics.FromImage(bmpPaint);

    gBoard.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

    for (int i = 0; i < row; i++)
    {
          for (int j = 0; j < line; j++)
          {
               string filePath = Application.StartupPath + @"\Resources\s" + numberArray[i, j].ToString() + ".png";
               //每种色子对应的图片名称。
               Bitmap bmpDice = new Bitmap(filePath);
               gBoard.DrawImage(bmpDice, gridSize * j + 30, gridSize * i + 30);
               bmpDice.Dispose();
           }
           System.Threading.Thread.Sleep(100);
     }

     for (int m = 0; m < line; m++)  //添加横纵坐标,方便查找
     {
         gBoard.DrawString((m + 1).ToString(), new Font("微软雅黑", 10), Brushes.Black, new Point(m * 30 + 30, 0));
         gBoard.DrawString((m + 1).ToString(), new Font("微软雅黑", 10), Brushes.Black, new Point(m * 30 + 30, row * 30 + 30));
      }
      for (int n = 0; n < row; n++)
      {
         gBoard.DrawString((n + 1).ToString(), new Font("微软雅黑", 10), Brushes.Black, new Point(0, n * 30 + 30));
         gBoard.DrawString((n + 1).ToString(), new Font("微软雅黑", 10), Brushes.Black, new Point(line * 30 + 30, n * 30 + 30));
       }

     return bmpPaint;
}

5.如果只是生成一张色子图片,上文中的代码已经够了,但是如果你真的想用色子把图片拼出来,那么还需要一个更直观的数据。

        public Bitmap DrawwithNumber(Int32[,] numberArray)
        {

            int gridSize = 30;
            Font f = new Font("微软雅黑", 9);
            Pen p = new Pen(Brushes.RoyalBlue, 2);
            int row = numberArray.GetLength(0);
            int line = numberArray.GetLength(1);
            Bitmap bmpPaint = new Bitmap(line * gridSize + gridSize * 3, row * gridSize + gridSize * 7);
            Graphics gBoard = Graphics.FromImage(bmpPaint);

            for (int i = 1; i <= line; i++)  //先把横纵坐标画出来
            {
                gBoard.DrawString(i.ToString(), f, Brushes.Black, new PointF(i * 30 + 5, 5));
                gBoard.DrawString(i.ToString(), f, Brushes.Black, new PointF(i * 30 + 5, row * gridSize + gridSize * 1));
            }
            for (int j = 1; j <= row; j++) //先把横纵坐标画出来
            {
                gBoard.DrawString(j.ToString(), f, Brushes.Black, new PointF(0, j * 30 + 5));
                gBoard.DrawString(j.ToString(), f, Brushes.Black, new PointF(line * gridSize + gridSize, j * 30 + 5));
            }

            for (int i = 0; i < row; i++)  //画方格和数字
            {
                for (int j = 0; j < line; j++)
                {
                    gBoard.DrawRectangle(p, gridSize * j + gridSize, gridSize * i + gridSize, 30, 30);
                    gBoard.DrawString(numberArray[i, j].ToString(), new Font("微软雅黑", 18), Brushes.Black, new PointF(gridSize * j + gridSize, gridSize * i + gridSize));

                }
            }
            return bmpPaint;
        }

效果图

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值