如何把一张图片上一部分单独保存为一个图片

快跑稻草人 2018-12-10 01:29:41
我有一张图,上边有很多个小图片,每个小图片是单独分开的,小图片之间的颜色是透明的,也就是alpha=0

我想把每个图片都分开保存。

我尝试着找到每个图片的边界,并用黑色线条框了起来,但是这些点我没有办法连贯起来。
我可以找到这个边界上的点,但是无法确定哪些点是同一个图形上的。


请问应该怎么把这些图片保存下来?

这些点只能找到是在边界上,但是我没有办法确定哪些点是同一个图形的点,只是有所有这些点的集合。
...全文
1651 32 打赏 收藏 转发到动态 举报
写回复
用AI写文章
32 条回复
切换为时间正序
请发表友善的回复…
发表回复
快跑稻草人 2018-12-14
  • 打赏
  • 举报
回复
引用 33 楼 xuzuning 的回复:
那是正常的,有多少图片中有透明通道呢???
引用 32 楼 快跑稻草人 的回复:
我今天测试您的代码,提示stackoverflow,经过修改之后,就这个图片能够正常显示,其他的图片都无法正常显示
这个不确定,其他的图片也跟这个不一样
xuzuning 2018-12-14
  • 打赏
  • 举报
回复
那是正常的,有多少图片中有透明通道呢???


引用 32 楼 快跑稻草人 的回复:
我今天测试您的代码,提示stackoverflow,经过修改之后,就这个图片能够正常显示,其他的图片都无法正常显示
快跑稻草人 2018-12-14
  • 打赏
  • 举报
回复
引用 25 楼 xuzuning 的回复:
        Bitmap src;
        List<Point> ps;
        byte[,] im;
        void Cut()
        {
            src = new Bitmap("t.png");//)pictureBox1.Image;
            //g.DrawImage(src, Point.Empty);
            //im = Enumerable.Repeat(new BitArray(src.Width).Not(), src.Height).ToList();
            im = new byte[src.Width, src.Height];
            for (var y = 0; y < src.Height; y++)
            {
                for (var x = 0; x < src.Width; x++)
                {
                    im[x, y] = (byte)(src.GetPixel(x, y).A == 0 ? 1 : 0);
                }
            }
            var n = 0;
            for (var y = 0; y < src.Height; y++)
            {
                for (var x = 0; x < src.Width; x++)
                {
                    if (im[x, y] == 0)
                    {
                        ps = marked(x, y).ToList();
                        Save(++n + ".png");
                    }
                }
            }
        }
        void Save(string fileName)
        {
            var x0 = (int)ps.Min(p => p.X);
            var y0 = (int)ps.Min(p => p.Y);
            var x1 = (int)ps.Max(p => p.X);
            var y1 = (int)ps.Max(p => p.Y);
            var bm = new Bitmap(x1 - x0 + 1, y1 - y0 + 1);
            foreach (var p in ps) bm.SetPixel(p.X - x0, p.Y - y0, src.GetPixel(p.X, p.Y));
            bm.Save(fileName, ImageFormat.Png);
        }
        IEnumerable<Point> marked(int x, int y)
        {
            //查找左端点
            var x1 = x;
            while (im[x1 - 1, y] == 0) x1--;
            //查找右端点
            var x2 = x;
            while (im[x2 + 1, y] == 0) x2++;
            //
            for (var i = x1; i <= x2; i++)
            {
                im[i, y] = 192;
                yield return new Point(i, y);
                if (y > 0 && im[i, y - 1] == 0) foreach (var p in marked(i, y - 1)) yield return p;
                if (y < im.GetLength(0)-1 && im[i, y + 1] == 0) foreach (var p in marked(i, y + 1)) yield return p;
            }
        }

不好意思,有事耽搁了 这是最慢但最容易理解的算法,自己去优化吧
我今天测试您的代码,提示stackoverflow,经过修改之后,就这个图片能够正常显示,其他的图片都无法正常显示
张天星 2018-12-13
  • 打赏
  • 举报
回复
简单,直接,明了
ID风清扬 2018-12-13
  • 打赏
  • 举报
回复
看起来挺复杂,搞不懂啊。
快跑稻草人 2018-12-12
  • 打赏
  • 举报
回复
引用 25 楼 xuzuning 的回复:
        Bitmap src;
        List<Point> ps;
        byte[,] im;
        void Cut()
        {
            src = new Bitmap("t.png");//)pictureBox1.Image;
            //g.DrawImage(src, Point.Empty);
            //im = Enumerable.Repeat(new BitArray(src.Width).Not(), src.Height).ToList();
            im = new byte[src.Width, src.Height];
            for (var y = 0; y < src.Height; y++)
            {
                for (var x = 0; x < src.Width; x++)
                {
                    im[x, y] = (byte)(src.GetPixel(x, y).A == 0 ? 1 : 0);
                }
            }
            var n = 0;
            for (var y = 0; y < src.Height; y++)
            {
                for (var x = 0; x < src.Width; x++)
                {
                    if (im[x, y] == 0)
                    {
                        ps = marked(x, y).ToList();
                        Save(++n + ".png");
                    }
                }
            }
        }
        void Save(string fileName)
        {
            var x0 = (int)ps.Min(p => p.X);
            var y0 = (int)ps.Min(p => p.Y);
            var x1 = (int)ps.Max(p => p.X);
            var y1 = (int)ps.Max(p => p.Y);
            var bm = new Bitmap(x1 - x0 + 1, y1 - y0 + 1);
            foreach (var p in ps) bm.SetPixel(p.X - x0, p.Y - y0, src.GetPixel(p.X, p.Y));
            bm.Save(fileName, ImageFormat.Png);
        }
        IEnumerable<Point> marked(int x, int y)
        {
            //查找左端点
            var x1 = x;
            while (im[x1 - 1, y] == 0) x1--;
            //查找右端点
            var x2 = x;
            while (im[x2 + 1, y] == 0) x2++;
            //
            for (var i = x1; i <= x2; i++)
            {
                im[i, y] = 192;
                yield return new Point(i, y);
                if (y > 0 && im[i, y - 1] == 0) foreach (var p in marked(i, y - 1)) yield return p;
                if (y < im.GetLength(0)-1 && im[i, y + 1] == 0) foreach (var p in marked(i, y + 1)) yield return p;
            }
        }

不好意思,有事耽搁了 这是最慢但最容易理解的算法,自己去优化吧
多谢,其实昨天我也已经做出来了
xuzuning 2018-12-12
  • 打赏
  • 举报
回复
        Bitmap src;
List<Point> ps;
byte[,] im;
void Cut()
{
src = new Bitmap("t.png");//)pictureBox1.Image;
//g.DrawImage(src, Point.Empty);
//im = Enumerable.Repeat(new BitArray(src.Width).Not(), src.Height).ToList();
im = new byte[src.Width, src.Height];
for (var y = 0; y < src.Height; y++)
{
for (var x = 0; x < src.Width; x++)
{
im[x, y] = (byte)(src.GetPixel(x, y).A == 0 ? 1 : 0);
}
}
var n = 0;
for (var y = 0; y < src.Height; y++)
{
for (var x = 0; x < src.Width; x++)
{
if (im[x, y] == 0)
{
ps = marked(x, y).ToList();
Save(++n + ".png");
}
}
}
}
void Save(string fileName)
{
var x0 = (int)ps.Min(p => p.X);
var y0 = (int)ps.Min(p => p.Y);
var x1 = (int)ps.Max(p => p.X);
var y1 = (int)ps.Max(p => p.Y);
var bm = new Bitmap(x1 - x0 + 1, y1 - y0 + 1);
foreach (var p in ps) bm.SetPixel(p.X - x0, p.Y - y0, src.GetPixel(p.X, p.Y));
bm.Save(fileName, ImageFormat.Png);
}
IEnumerable<Point> marked(int x, int y)
{
//查找左端点
var x1 = x;
while (im[x1 - 1, y] == 0) x1--;
//查找右端点
var x2 = x;
while (im[x2 + 1, y] == 0) x2++;
//
for (var i = x1; i <= x2; i++)
{
im[i, y] = 192;
yield return new Point(i, y);
if (y > 0 && im[i, y - 1] == 0) foreach (var p in marked(i, y - 1)) yield return p;
if (y < im.GetLength(0)-1 && im[i, y + 1] == 0) foreach (var p in marked(i, y + 1)) yield return p;
}
}


不好意思,有事耽搁了
这是最慢但最容易理解的算法,自己去优化吧
叫我于66 2018-12-12
  • 打赏
  • 举报
回复
学到了。。。。。
jingzhen_csdn 2018-12-12
  • 打赏
  • 举报
回复
大牛人。俺都看不懂。好厉害的样子呢。。。
刁雷 2018-12-11
  • 打赏
  • 举报
回复
用PS找到魔棒功能
qq_38912052 2018-12-11
  • 打赏
  • 举报
回复
看看学习一下
qq_33207538 2018-12-11
  • 打赏
  • 举报
回复
真棒,非常好
鹏达广告 2018-12-11
  • 打赏
  • 举报
回复
发出来原图我看看
不然哪个知道啥情况?
Horae时序女神 2018-12-11
  • 打赏
  • 举报
回复
PNG格式的吗?最笨的办法是新建一个透明背景,然后复制一个图片上去保存就可以了,直到把你要的小图片都保存完。大功告成!
xuzuning 2018-12-11
  • 打赏
  • 举报
回复
待会给你发个完整的示例
我的兜里有糖 2018-12-11
  • 打赏
  • 举报
回复
用PS截取一下然后保存成PNG格式?
快跑稻草人 2018-12-11
  • 打赏
  • 举报
回复
引用 11 楼 xuzuning 的回复:
讨论需要有共同的基点,讨论中也会书写一些代码。你一直强调存在 alpha=0 的点(因为他最容易被识别),如果有原始图片的话,就会使讨论变得容易了,且讨论的结果也可直接应用于实践,从而避免因算法调整带来的问题 其实算法也很简单,就是最常见的扫描线联通区域识别法(你也可以用轮廓追踪法,但无法识别出图形中的空洞) 大致这样
        IEnumerable<Point> marked(int x, int y)
        {
            var im = this;
            //查找左端点
            var x1 = x;
            while (im[x1 - 1, y] == 0) x1--;
            //查找右端点
            var x2 = x;
            while (im[x2 + 1, y] == 0) x2++;
            //
            for (var i = x1; i <= x2; i++)
            {
                im[i, y] = 192;//标记一下,避免重复测试
                yield return new Point(i, y);
                if (im[i, y - 1] == 0) foreach (var p in marked(i, y - 1)) yield return p;
                if (im[i, y + 1] == 0) foreach (var p in marked(i, y + 1)) yield return p;
            }
        }
得到联通区域中的所有的点
我对您这个代码不太理解,可否详细说一下?
快跑稻草人 2018-12-11
  • 打赏
  • 举报
回复
引用 14 楼 xuzuning 的回复:
待会给你发个完整的示例
请问一下,示例有了没有?
qq_40291238 2018-12-11
  • 打赏
  • 举报
回复
感觉一下子学习到了很多
快跑稻草人 2018-12-11
  • 打赏
  • 举报
回复
引用 14 楼 xuzuning 的回复:
待会给你发个完整的示例
谢谢
加载更多回复(12)

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧