文档章节

Spuria - 一个用C#写的让图片边缘颜色变浅的工具

北风其凉
 北风其凉
发布于 2014/09/11 14:49
字数 1143
阅读 103
收藏 0
点赞 0
评论 0

一、Spuria编写目的

昨天晚上因为需要把一些照片的边缘变亮(或者说变浅),突然有了写一个程序去处理的想法。Spuria可以读取一张图片,将图片的边缘部分加亮,然后将处理后的图片保存到用户指定的位置。

Spuria下载地址:http://pan.baidu.com/s/1gdFxIdt

原图片与处理后图片的对比:

二、图片加亮的方法

因为我也没有太多图片处理方面的编程经验,用的方法比较笨,就是逐个像素地处理。

我用的方法以一张图片的左上角为例:

处理后的图片比较大,是本程序的一个缺点。新图片用QQ截图后再保存可以得到一张看上去一样但小得多的图片

三、界面设计

控件TrackBar:tkbDepth

用来调节图片变量的深度,数值越大,程序就会在图像边缘越大的地区进行渐变处理

控件ProgressBar:pgbTmp

是程序处理图片时临时显示的处理进度条

用户可以单击浏览按钮从磁盘中读取图片,左侧显示原图片,右侧显示当前处理后的图片。

通过tkbDepth将右侧图片调整满意后单击保存按钮将生成后的文件保存到磁盘。

四、程序代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Spuria
{
    public partial class SpuriaTool : Form
    {
        #region 窗体初始化

        public SpuriaTool()
        {
            InitializeComponent();
        }

        private void SpuriaTool_Load(object sender, EventArgs e)
        {
            //初始化默认图片
            if (pcbLeft.Image != null)
            {
                //初始化右侧修改后图片:按TrackBar的值进行修改
                pcbRight.Image = null;
                pcbRight.Image = LightenMargin(
                    pcbLeft.Image.Clone() as Bitmap, tkbDepth.Value);
            }
        }

        #endregion
        #region 控件事件

        //读入一张新图片
        private void btnBrowse_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            
            ofd.AutoUpgradeEnabled = true;
            ofd.CheckFileExists = true;
            ofd.CheckPathExists = true;
            ofd.ReadOnlyChecked = false;
            ofd.Multiselect = false;
            ofd.FileName = "";
            ofd.Filter = "PNG|*.png|BMP|*.bmp|JPG|*.jpg|GIF|*.gif";
            ofd.Title = "打开图片";

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    //显示读入图片地址,初始化左侧图片框
                    txtAddress.Text = ofd.FileName;
                    pcbLeft.Load(ofd.FileName);

                    //在右侧图片框中展示修改后的图片
                    pcbRight.Image = LightenMargin(
                        pcbLeft.Image.Clone() as Bitmap, 10);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
        }

        //将修改后的图片保存到磁盘
        private void btnSave_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();

            sfd.OverwritePrompt = true;
            sfd.Filter = "PNG|*.png|BMP|*.bmp|JPEG|*.jpeg|GIF|*.gif";
            sfd.FileName = string.Concat("Spuria_",
                DateTime.Now.Year.ToString("#0000"),
                DateTime.Now.Month.ToString("#00"),
                DateTime.Now.Day.ToString("#00"),
                DateTime.Now.Hour.ToString("#00"),
                DateTime.Now.Minute.ToString("#00"),
                DateTime.Now.Second.ToString("#00"));
            sfd.Title = "保存图片";

            if (sfd.ShowDialog() == DialogResult.OK)
            {
                switch (sfd.FilterIndex)
                {
                    case 0:
                        {
                            pcbRight.Image.Save(sfd.FileName,
                                System.Drawing.Imaging.ImageFormat.Png);
                        }
                        break;
                    case 1:
                        {
                            pcbRight.Image.Save(sfd.FileName,
                                System.Drawing.Imaging.ImageFormat.Bmp);
                        }
                        break;
                    case 2:
                        {
                            pcbRight.Image.Save(sfd.FileName,
                                System.Drawing.Imaging.ImageFormat.Jpeg);
                        }
                        break;
                    case 3:
                        {
                            pcbRight.Image.Save(sfd.FileName,
                                System.Drawing.Imaging.ImageFormat.Gif);
                        }
                        break;
                    default: 
                        break;
                }
            }
        }

        //当鼠标从TrackBar上松开时触发
        private void tkbDepth_MouseUp(object sender, MouseEventArgs e)
        {
            if (pcbLeft.Image != null)
            {
                pcbRight.Image = null;
                pcbRight.Image = LightenMargin(
                    pcbLeft.Image.Clone() as Bitmap, tkbDepth.Value);
            }
        }

        #endregion 控件
        #region 相关函数

        /// <summary>
        /// 将一个Bitmap图片的边缘加亮
        /// </summary>
        /// <param name="bitmap">原图片</param>
        /// <param name="depth">加亮深度</param>
        /// <returns>加亮后图片</returns>
        public Bitmap LightenMargin(Bitmap bitmap, int depth)
        {
            //输入合法性检查
            if (bitmap == null) return null;
            if (depth <= 0) return bitmap;

            //显示进度条
            pgbTemp.Visible = true;
            pgbTemp.Value = 0;

            Bitmap result = new Bitmap(bitmap.Width, bitmap.Height);

            //minx:横向到边框的最短距离 miny:纵向到边框的最短距离
            int minx, miny, mindistance;
            float coefficient;
            for (int i = 0; i < bitmap.Width; i++)
            {
                for (int j = 0; j < bitmap.Height; j++)
                {
                    minx = i < bitmap.Width - i ? i : bitmap.Width - i;
                    miny = j < bitmap.Height - j ? j : bitmap.Height - j;

                    //四个角的情况,作与两边相切半径为depth的四个圆
                    if (minx <= depth && miny <= depth)
                    {
                        mindistance =
                            (int)Math.Sqrt(
                            (depth - minx) * (depth - minx) +
                            (depth - miny) * (depth - miny));

                        //距离圆心距离小于等于depth则渐变(越远离圆心越淡)
                        if (mindistance <= depth)
                        {
                            coefficient = 1.0f * mindistance / depth;
                            result.SetPixel(i, j, AdjustBrightness(
                                bitmap.GetPixel(i, j), coefficient));
                        }
                        //距离圆心距离大于depth则置白
                        else
                        {
                            result.SetPixel(i, j, Color.FromArgb(
                                bitmap.GetPixel(i, j).A, 255, 255, 255));
                        }
                    }
                    //四条边的情况(越靠近边越淡)
                    else if (minx <= depth || miny <= depth)
                    {
                        mindistance = minx < miny ? minx : miny;
                        coefficient = 1.0f - (1.0f * mindistance / depth);
                        result.SetPixel(i, j,
                            AdjustBrightness(bitmap.GetPixel(i, j), coefficient));
                    }
                    //图片中心部分的情况(不处理)
                    else
                    {
                        result.SetPixel(i, j, bitmap.GetPixel(i, j));
                    }

                    //刷新进度条
                    pgbTemp.Value = 100 * i / bitmap.Width;
                }
            }

            //函数运行完毕,隐藏进度条
            pgbTemp.Visible = false;

            return result;
        }

        /// <summary>
        /// 改变一个点的颜色:变亮或变暗
        /// </summary>
        /// <param name="color">被改变颜色</param>
        /// <param name="coefficient">颜色调整系数:-1f时颜色最浅,1f时颜色最深</param>
        /// <returns>改变后颜色</returns>
        public static Color AdjustBrightness(Color color, float coefficient)
        {
            if (coefficient < -1f) coefficient = -1f;
            if (coefficient > 1f) coefficient = 1f;

            float red = (float)color.R;
            float green = (float)color.G;
            float blue = (float)color.B;

            if (coefficient < 0)
            {
                coefficient = 1 + coefficient;
                red *= coefficient;
                green *= coefficient;
                blue *= coefficient;
            }
            else
            {
                red = (255 - red) * coefficient + red;
                green = (255 - green) * coefficient + green;
                blue = (255 - blue) * coefficient + blue;
            }

            red = red > 0 ? red : 0;
            red = red < 255 ? red : 255;
            green = green > 0 ? green : 0;
            green = green < 255 ? green : 255;
            blue = blue > 0 ? blue : 0;
            blue = blue < 255 ? blue : 255;

            return Color.FromArgb(color.A, (int)red, (int)green, (int)blue);
        }

        #endregion
    }
}

END

© 著作权归作者所有

共有 人打赏支持
北风其凉

北风其凉

粉丝 114
博文 497
码字总数 462457
作品 4
朝阳
程序员
QiZW/ColorUtils

ColorUtils Android中的颜色工具,可以实现颜色变化,颜色透明度变化,颜色格式转换,颜色格式判断等。 效果展示(输入颜色值->更换主题颜色) 注意 Android下的颜色为16进制的ARGB(Alpha,...

QiZW
2017/07/19
0
0
PNG尺寸缩小实战

为了节省资源,我们希望在不同分辨率的前端上可以获取到不同尺寸的素材资源。由于最近的业务中使用的所有素材都是PNG格式的图片,并且对图片效果要求比较严格,并没有在市面上找到可以直接使...

EchoZhou
2017/11/29
0
0
如何解决ABBYY中区域未正确检测问题

 ABBYY FineReader会在识别前分析页面图像并检测图片上不同类型的区域,如文本、图片、背景图片、表格和条形码区域,此分析确定识别的区域和识别顺序。在用户界面中,不同的区域类型按其边界...

ABBYY
2016/04/06
54
0
【UnityShader】字符画风格屏幕后处理

原理 在UnityShader中实现字符画,实际工作就是把原图像分成矩阵块,分析每个每个块内的图像,并替换为字符。 图像的分析方法最简单的就是灰度值,在字符密度较大时能以很简单的方式达到效果...

qq_37043683
04/23
0
0
7- OpenCV+TensorFlow 入门人工智能图像处理-彩色反转&边缘检测

彩色图像的颜色反转 不管是灰度图像的颜色反转,还是彩色颜色反转。都是255减去当前值 马赛克效果 理解马赛克效果中的关键指标 马赛克效果的窗体范围。如: 从100行开始到300行结束,列从100...

天涯明月笙
05/06
0
0
imagick图片处理

ImageMagick是一个免费的创建、编辑、合成图片的软件。它可以读取、转换、写入多种格式的图片。图片切割、颜色替换、各种效果的应用,图片的旋转、组合,文本,直线,多边形,椭圆,曲线,附...

嚣张乾坤
2015/10/17
339
1
怎么使用 SVG 作为一个图像占位符

从图像中生成的 SVG 可以用作占位符。请继续阅读! 我对怎么去让 web 性能更优化和图像加载的更快充满了热情。在这些感兴趣的领域中的其中一项研究就是占位符:当图像还没有被加载的时候应该...

作者: José M. Pérez
2017/12/13
0
0
8- OpenCV+TensorFlow 入门人工智能图像处理-浮雕效果&油画效果

浮雕效果 浮雕效果与边缘检测类似,也是计算梯度的一个过程 计算公式: 加上150是为了增强图片的浮雕灰度等级。 相邻像素相减,是为了突出灰度的突片。边缘特征。 代码实现 150就是当前的灰度值...

天涯明月笙
05/07
0
0
canvas实现的擦除效果

嗯,好久没有写博客了,因为较长一段时间发生了点点变故:楼主从传统IT项目(OA)跳到了移动端,主要搞微信上的web开发,也是学习了很长一段时间。 言归正传,微信上常见的手指滑动扣个圈圈,...

The-Dawn
2016/05/16
339
1
C# WinForm开发系列 - GDI+

UI(User Interface)编程在整个项目开发过程中是个颇为重要的环节,任何好的解决方案若没有良好的用户界面呈现给最终用户,那么就算包含了最先进的技术也不能算是好程序。UI编程体现在两个方...

长征2号
2017/11/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

编程语言对比分析:Python与Java和JavaScript(图)

编程语言对比分析:Python与Java和JavaScript(图): 凭什么说“Python 太慢,Java 太笨拙,我讨厌 JavaScript”?[图] 编程语言生而为何? 我们人类从原始社会就是用语言表达自己,互相沟通...

原创小博客
10分钟前
0
0
Akka构建Reactive应用《one》

看到这Akka的官网,描述使用java或者scala构建响应式,并发和分布式应用更加简单,听着很高级的样子,下面的小字写着消息驱动,但是在quickstart里面又写容错事件驱动,就是这么钻牛角尖。 ...

woshixin
22分钟前
0
0
ffmpeg源码分析 (四)

io_open 承接上一篇,对于avformat_open_input的分析还差其中非常重要的一步,就是io_open,该函数用于打开FFmpeg的输入输出文件。 在init_input中有这么一句 if ((ret = s->io_open(s, &s-...

街角的小丑
24分钟前
0
0
String,StringBuffer ,StringBuilder的区别

不同点 一、基类不同 StringBuffer、StringBuilder 都继承自AbStractStringBuilder,String 直接继承自 Object 2、底层容器“不同” 虽然底层都是字符数组,但是String的是final修饰的不可变...

不开心的时候不要学习
39分钟前
0
0
nodejs 文件操作

写文件code // 加载文件模块var fs = require("fs");var content = 'Hello World, 你好世界!';//params 文件名,内容,编码,回调fs.writeFile('./hello.txt',content,'utf8',function (er......

yanhl
41分钟前
0
0
SpringBoot mybits 查询为0条数据 但是在Navicat 中可以查询到数据

1.页面请求: 数据库查询: 2018-07-16 17:56:25.054 DEBUG 17312 --- [nio-9010-exec-3] c.s.h.m.C.selectSelective : ==> Preparing: select id, card_number, customer_id, customer_nam......

kuchawyz
51分钟前
0
0
译:Self-Modifying cod 和cacheflush

date: 2014-11-26 09:53 翻译自: http://community.arm.com/groups/processors/blog/2010/02/17/caches-and-self-modifying-code Cache处在CPU核心与内存存储器之间,它给我们的感觉是,它具......

我叫半桶水
53分钟前
0
0
Artificial Intelligence Yourself

TensorFlow是谷歌基于DistBelief进行研发的第二代人工智能学习系统,其命名来源于本身的运行原理。Tensor(张量)意味着N维数组,Flow(流)意味着基于数据流图的计算,TensorFlow为张量从流...

孟飞阳
今天
0
0
press.one个人数字签名

这是我在press.one的数字签名 https://press.one/p/address/v?s=9d3d5b7ce019af357ab994775549e8f047a5b17fc9893364652fc67e4b95443b38ccb24c6655e0d252dd0154369eb9b7717c4ccf4e1835ca3596......

NateHuang
今天
1
0
Oracle 中的 SQL 分页查询原理和方法详解

本文分析并介绍 Oracle 中的分页查找的方法。 Oracle 中的表,除了我们建表时设计的各个字段,其实还有两个字段(此处只介绍2个),分别是 ROWID(行标示符)和 ROWNUM(行号),即使我们使用...

举个_栗子
今天
4
2

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部