[C#]根据labelme产生的json文件,批量生成8位黑白png图
目录
背景
软件环境
黑白图像素填充原理
源码
示例图片
附录:
1.调试带参数的控制台应用程序方法
2. 使用pyinstaller将labelme打包为exe文件
3. 数据标注软件labelme详解
背景
由于工作原因,需要对图像进行分类,建模,作为深度学习的材料。自己造轮子造了半天,结果发现labelme这块做的很好,于是放弃造轮子,借用labelme产生的json文件,生成需要的8位黑白png图(labelme自带的生成8位png图是彩色的,不满足需求)。
软件环境
Win10 python3.8.2 labelme4.2.10 pyqt5.14.1 pip-20.0.2
黑白图像素填充原理
根据json文件中的label标签,随机生成不同的1-255之间的数值,作为region的像素值。背景像素全为0
源码
解析JSON文件,我添加了Newtonsoft.Json.dll引用。可以直接在NuGet中搜索添加。
System.Drawing也需要在“程序集-框架”中添加。
以下为程序源码
Program.cs文件
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;using Newtonsoft.Json;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;namespace labelme_Json_to_png8
{class Program{/// /// 根据labelme-4.2.10产生的json文件批量生成png图片/// /// static void Main(string[] args){if(args.Length==2){string strPathSrc = args[0]; //labelme产生的JSON文件所在文件夹string strPathDes = args[1]; //产生的PNG文件存放的文件夹try{List srcFileNames = labelmeJson.GetJsonfiles(strPathSrc);int srcNum = srcFileNames.Count;for (int i = 0; i < srcNum; i++){string strDes = Path.Combine(strPathDes, Path.GetFileNameWithoutExtension(srcFileNames[i])+".png");//desFileNames.Add(str);labelmeJson.CreateImage(srcFileNames[i], strDes);}Console.WriteLine("Convert OK! 目标文件夹地址:" + strPathDes);}catch(Exception ex){Console.WriteLine(ex.ToString());}Console.ReadKey();}}}
}
labelmeJson.cs文件
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;using Newtonsoft.Json;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;namespace labelme_Json_to_png8
{public class labelmeJson{private static PointF[] GetPointFs(List> listDou){int inum = listDou.Count;PointF[] pointf = new PointF[inum];for (int i = 0; i < inum; i++){PointF p = new PointF();p.X = (float)listDou[i][0];p.Y = (float)listDou[i][1];pointf[i] = p;}return pointf;}/// /// 随机给各个region赋1-255之间像素值,背景色像素值为0/// /// /// /// public static bool CreateImage(string strSourcePath, string strDesPath){try{string jsonstr = File.ReadAllText(strSourcePath);LabelmeJsonObject lbjs = JsonConvert.DeserializeObject(jsonstr);//确保图像的宽度是4的倍数int imageWidth = int.Parse(lbjs.imageWidth);int imageHeight = int.Parse(lbjs.imageHeight);Bitmap bit = new Bitmap(imageWidth, imageHeight);Graphics dc = Graphics.FromImage(bit);dc.Clear(Color.Black);Dictionary dicLabel_Val = new Dictionary();Random random = new Random();foreach (Shapes shape in lbjs.shapes){string label = shape.label; if (!dicLabel_Val.Keys.Contains(label)){int num = random.Next(1, 255);dicLabel_Val.Add(label, num);}}foreach (Shapes shape in lbjs.shapes){int rval = dicLabel_Val[shape.label];if (shape.shape_type == "polygon"){PointF[] pointf = GetPointFs(shape.points);dc.FillPolygon(new SolidBrush(Color.FromArgb(rval, 0, 0)), pointf);dc.Save();}else if (shape.shape_type == "linestrip"){PointF[] pointf = GetPointFs(shape.points);dc.DrawLines(new Pen(new SolidBrush(Color.FromArgb(rval, 0, 0))), pointf);dc.Save();}else if (shape.shape_type == "rectangle"){PointF[] pointf = GetPointFs(shape.points);Rectangle rect = new Rectangle((int)pointf[0].X, (int)pointf[0].Y, (int)(pointf[1].X - pointf[0].X), (int)(pointf[1].Y - pointf[0].Y));dc.FillRectangle(new SolidBrush(Color.FromArgb(rval, 0, 0)), rect);dc.Save();}else if (shape.shape_type == "circle"){PointF[] pointf = GetPointFs(shape.points);double f = Math.Pow((pointf[1].X - pointf[0].X), 2) + Math.Pow((pointf[1].Y - pointf[0].Y), 2);float r = (float)Math.Sqrt(f);dc.FillEllipse(new SolidBrush(Color.FromArgb(rval, 0, 0)), pointf[0].X, pointf[0].Y, r, r);dc.Save();}else if (shape.shape_type == "point"){PointF[] pointf = GetPointFs(shape.points);dc.FillEllipse(new SolidBrush(Color.FromArgb(rval, 0, 0)), pointf[0].X, pointf[0].Y, 2, 2);dc.Save();}}Bitmap bmp = RgbToR8(bit);bmp.Save(strDesPath, ImageFormat.Png);}catch (Exception ex){Console.WriteLine(ex.ToString());return false;}return true;}/// /// 获取当前目录下所有的json文件/// /// /// public static List GetJsonfiles(string strPath){List list = new List();DirectoryInfo theFolder = new DirectoryInfo(strPath); // 给出你的目录文件位置 FileInfo[] fileInfo = theFolder.GetFiles(); // 获得当前的文件夹内的所有文件数组foreach (FileInfo NextFile in fileInfo) //遍历文件{if (NextFile.Extension.ToLower() == ".json") // 得到你想要的格式{list.Add(NextFile.FullName); // 用于测试输出}}return list;}/// /// 取源图像R通道数据,并转化为8位单像素图像。/// /// 源图像。 /// 8位单像素图像。 public static Bitmap RgbToR8(Bitmap original){if (original != null){// 将源图像内存区域锁定Rectangle rect = new Rectangle(0, 0, original.Width, original.Height);BitmapData bmpData = original.LockBits(rect, ImageLockMode.ReadOnly,PixelFormat.Format24bppRgb);// 获取图像参数int width = bmpData.Width;int height = bmpData.Height;int stride = bmpData.Stride; // 扫描线的宽度,比实际图片要大int offset = stride - width * 3; // 显示宽度与扫描线宽度的间隙IntPtr ptr = bmpData.Scan0; // 获取bmpData的内存起始位置的指针 int scanBytesLength = stride * height; // 用stride宽度,表示这是内存区域的大小// 分别设置两个位置指针,指向源数组和目标数组int posScan = 0, posDst = 0;byte[] rgbValues = new byte[scanBytesLength]; // 为目标数组分配内存Marshal.Copy(ptr, rgbValues, 0, scanBytesLength); // 将图像数据拷贝到rgbValues中// 分配单像素数组byte[] grayValues = new byte[width * height]; // 不含未用空间。// 计算单像素数组byte blue, green, red;for (int i = 0; i < height; i++){for (int j = 0; j < width; j++){blue = rgbValues[posScan];green = rgbValues[posScan + 1];red = rgbValues[posScan + 2];grayValues[posDst] = red;posScan += 3;posDst++;}// 跳过图像数据每行未用空间的字节,length = stride - width * bytePerPixelposScan += offset;}// 内存解锁Marshal.Copy(rgbValues, 0, ptr, scanBytesLength);original.UnlockBits(bmpData); // 解锁内存区域// 构建8位单像素位图Bitmap retBitmap = BuiltGrayBitmap(grayValues, width, height);return retBitmap;}else{return null;}}/// /// 用数组新建一个8位图像。/// /// 像素数组(length = width * height)。 /// 图像宽度。 /// 图像高度。 /// 新建的8位单像素位图。 private static Bitmap BuiltGrayBitmap(byte[] rawValues, int width, int height){// 新建一个8位位图,并锁定内存区域操作Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format8bppIndexed);BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, width, height),ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);// 计算图像参数int offset = bmpData.Stride - bmpData.Width; // 计算每行未用空间字节数IntPtr ptr = bmpData.Scan0; // 获取首地址int scanBytes = bmpData.Stride * bmpData.Height; // 图像字节数 = 扫描字节数 * 高度byte[] grayValues = new byte[scanBytes]; // 为图像数据分配内存// 为图像数据赋值int posSrc = 0, posScan = 0; // rawValues和grayValues的索引for (int i = 0; i < height; i++){for (int j = 0; j < width; j++){grayValues[posScan++] = rawValues[posSrc++];}// 跳过图像数据每行未用空间的字节,length = stride - width * bytePerPixelposScan += offset;}// 内存解锁Marshal.Copy(grayValues, 0, ptr, scanBytes);bitmap.UnlockBits(bmpData); // 解锁内存区域// 修改生成位图的索引表,从伪彩修改为单像素ColorPalette palette;// 获取一个Format8bppIndexed格式图像的Palette对象using (Bitmap bmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed)){palette = bmp.Palette;}for (int i = 0; i < 256; i++){palette.Entries[i] = Color.FromArgb(i, i, i);}// 修改生成位图的索引表bitmap.Palette = palette;return bitmap;}}public class Flags { } public class Shapes{public string label { get; set; }public List> points { get; set; }public string group_id { get; set; }public string shape_type { get; set; }public Flags flags { get; set; }}public class LabelmeJsonObject{public string version { get; set; }public Flags flags { get; set; }public List shapes { get; set; }public string imagePath { get; set; }public string imageData { get; set; }public string imageHeight { get; set; }public string imageWidth { get; set; }}
}
示例图片
附录:
1.调试带参数的控制台应用程序方法
在项目属性中选中 “调试” 页,在 “启动选项-命令行参数”栏中写入 json文件所在文件夹 和 产生的png文件保存的文件夹。和在cmd中输入参数格式一样,注意其中的空格。例如:d:/img/json d:/img/json/png
在“启动选项-工作目录”栏中,选择程序所在目录,例如:程序的debug目录。
2. 使用pyinstaller将labelme打包为exe文件
https://blog.csdn.net/weixin_44001860/article/details/103746555
3. 数据标注软件labelme详解
https://blog.csdn.net/u014061630/article/details/88756644
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!