[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

 

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部