BioLib  4.1.1
A GUI-less version of Bio .NET library for editing & annotating various microscopy image formats.
Loading...
Searching...
No Matches
BioLib.NumPy Class Reference

Classes

class  NpyHeader
 

Public Types

enum  NpyDataType {
  UInt8 = 1 , Int8 = 2 , UInt16 = 3 , Int16 = 4 ,
  UInt32 = 5 , Int32 = 6 , UInt64 = 7 , Int64 = 8 ,
  Float16 = 9 , Float32 = 10 , Float64 = 11 , Complex64 = 12 ,
  Complex128 = 13
}
 

Static Public Member Functions

static string GetNpyTypeString (NpyDataType type)
 
static NpyDataType GetNpyTypeEnum (string type)
 
static void SaveNumPy (BioImage b, string file)
 
static TArray ConvertToMultidimensional< T, TArray > (Array flatArray, int[] shape)
 Converts a flat array into a multi-dimensional array based on the given shape.
 
static Array ReadNpyFile (string filePath)
 
static int GetElementSize (NpyDataType type)
 Helper function to get the size of the elements based on dtype.
 
static T ConvertJaggedArray< T > (Array jaggedArray)
 
static T CreateJaggedArray< T > (int[] shape, T[] data, int dimension)
 
static Array ConvertBytesToTypedArray (byte[] data, NpyDataType dataType)
 

Static Public Attributes

static int []
 
static NpyDataType
 

Member Enumeration Documentation

◆ NpyDataType

enum BioLib.NumPy.NpyDataType
1167 {
1168 // Integer types
1169 UInt8 = 1, // |u1
1170 Int8 = 2, // |i1
1171 UInt16 = 3, // |u2
1172 Int16 = 4, // |i2
1173 UInt32 = 5, // |u4
1174 Int32 = 6, // |i4
1175 UInt64 = 7, // |u8
1176 Int64 = 8, // |i8
1177
1178 // Floating point types
1179 Float16 = 9, // |f2
1180 Float32 = 10, // |f4
1181 Float64 = 11, // |f8
1182
1183 // Complex number types (optional depending on your use case)
1184 Complex64 = 12, // |c8
1185 Complex128 = 13 // |c16
1186 }

Member Function Documentation

◆ ConvertBytesToTypedArray()

static Array BioLib.NumPy.ConvertBytesToTypedArray ( byte[] data,
NpyDataType dataType )
static
1682 {
1683 switch (dataType)
1684 {
1685 case NpyDataType.UInt8:
1686 return ConvertByteArrayToUInt8(data);
1687 case NpyDataType.Int8:
1688 return ConvertByteArrayToInt8(data);
1689 case NpyDataType.UInt16:
1690 return ConvertByteArrayToUInt16(data);
1691 case NpyDataType.Int16:
1692 return ConvertByteArrayToInt16(data);
1693 case NpyDataType.UInt32:
1694 return ConvertByteArrayToUInt32(data);
1695 case NpyDataType.Int32:
1696 return ConvertByteArrayToInt32(data);
1697 case NpyDataType.UInt64:
1698 return ConvertByteArrayToUInt64(data);
1699 case NpyDataType.Int64:
1700 return ConvertByteArrayToInt64(data);
1701 case NpyDataType.Float16:
1702 return ConvertByteArrayToFloat16(data);
1703 case NpyDataType.Float32:
1704 return ConvertByteArrayToFloat32(data);
1705 case NpyDataType.Float64:
1706 return ConvertByteArrayToFloat64(data);
1707 case NpyDataType.Complex64:
1708 return ConvertByteArrayToComplex64(data);
1709 case NpyDataType.Complex128:
1710 return ConvertByteArrayToComplex128(data);
1711 default:
1712 throw new ArgumentException("Unsupported data type", nameof(dataType));
1713 }
1714 }

◆ ConvertJaggedArray< T >()

static T BioLib.NumPy.ConvertJaggedArray< T > ( Array jaggedArray)
static
1589 {
1590 // Ensure the provided array is of the correct jagged array type
1591 if (jaggedArray is int[][] jagged)
1592 {
1593 int rows = jagged.Length;
1594 int cols = jagged[0].Length;
1595
1596 // Create an instance of the desired 2D array using reflection
1597 T result = (T)Activator.CreateInstance(typeof(T), new object[] { rows, cols });
1598
1599 // Copy values from jagged array to the newly created 2D array
1600 for (int i = 0; i < rows; i++)
1601 {
1602 for (int j = 0; j < cols; j++)
1603 {
1604 // Use reflection to set the value in the result array
1605 var element = result.GetType().GetElementType();
1606 result.GetType().GetMethod("SetValue").Invoke(result, new object[] { jagged[i][j], i, j });
1607 }
1608 }
1609
1610 return result;
1611 }
1612
1613 throw new InvalidCastException("The input array is not of the expected type.");
1614 }

◆ ConvertToMultidimensional< T, TArray >()

static TArray BioLib.NumPy.ConvertToMultidimensional< T, TArray > ( Array flatArray,
int[] shape )
static

Converts a flat array into a multi-dimensional array based on the given shape.

Template Parameters
TType of the elements in the array.
TArrayType of the target multi-dimensional array.
Parameters
flatArrayThe flat array containing the data.
shapeThe shape of the target multi-dimensional array.
Returns
The multi-dimensional array.
1349 {
1350 if (flatArray.Length != shape.Aggregate(1, (a, b) => a * b))
1351 throw new ArgumentException("The shape does not match the length of the flat array.");
1352
1353 var result = (Array)Array.CreateInstance(typeof(T), shape);
1354
1355 int[] indices = new int[shape.Length];
1356 for (int i = 0; i < flatArray.Length; i++)
1357 {
1358 // Compute the multi-dimensional indices
1359 int offset = i;
1360 for (int j = shape.Length - 1; j >= 0; j--)
1361 {
1362 indices[j] = offset % shape[j];
1363 offset /= shape[j];
1364 }
1365
1366 // Set the value in the multi-dimensional array
1367 result.SetValue(flatArray.GetValue(i), indices);
1368 }
1369
1370 return (TArray)(object)result;
1371 }

◆ CreateJaggedArray< T >()

static T BioLib.NumPy.CreateJaggedArray< T > ( int[] shape,
T[] data,
int dimension )
static
Type Constraints
T :struct 
1616 : struct
1617 {
1618 // Base case: if we reached the last dimension, return the data array for that dimension
1619 if (dimension == shape.Length - 1)
1620 {
1621 // Create a 2D array for the last dimension
1622 T[,] array = (T[,])Activator.CreateInstance(typeof(T[,]), shape[dimension], data.Length / shape[dimension]);
1623 Array.Copy(data, array, data.Length); // Copy data into the array
1624 return (T)(object)array; // Cast to T (we will handle this later)
1625 }
1626
1627 // Recursive case: create jagged array for higher dimensions
1628 int subDimensionSize = shape[dimension + 1];
1629 int firstDimLength = shape[dimension];
1630
1631 // Create a jagged array for the current dimension
1632 Array jaggedArray = Array.CreateInstance(typeof(Array), shape[dimension]);
1633
1634 int index = 0;
1635 for (int i = 0; i < firstDimLength; i++)
1636 {
1637 // Recursively create the sub-arrays
1638 var subArray = CreateJaggedArray(shape, data.Skip(index).Take(subDimensionSize).ToArray(), dimension + 1);
1639 jaggedArray.SetValue(subArray, i); // Set the sub-array at index
1640 index += subDimensionSize;
1641 }
1642
1643 // Return the jagged array
1644 return (T)System.Convert.ChangeType(jaggedArray, typeof(T)); // Use Convert.ChangeType to cast System.Array to T
1645 }

◆ GetElementSize()

static int BioLib.NumPy.GetElementSize ( NpyDataType type)
static

Helper function to get the size of the elements based on dtype.

Parameters
dtype
Returns
1549 {
1550 switch (type)
1551 {
1552 case NpyDataType.UInt8:
1553 case NpyDataType.Int8:
1554 return 1; // 1 byte for UInt8 and Int8
1555
1556 case NpyDataType.UInt16:
1557 case NpyDataType.Int16:
1558 return 2; // 2 bytes for UInt16 and Int16
1559
1560 case NpyDataType.UInt32:
1561 case NpyDataType.Int32:
1562 return 4; // 4 bytes for UInt32 and Int32
1563
1564 case NpyDataType.UInt64:
1565 case NpyDataType.Int64:
1566 return 8; // 8 bytes for UInt64 and Int64
1567
1568 case NpyDataType.Float16:
1569 return 2; // 2 bytes for Float16
1570
1571 case NpyDataType.Float32:
1572 return 4; // 4 bytes for Float32
1573
1574 case NpyDataType.Float64:
1575 return 8; // 8 bytes for Float64
1576
1577 case NpyDataType.Complex64:
1578 return 8; // 8 bytes for Complex64 (2 * Float32)
1579
1580 case NpyDataType.Complex128:
1581 return 16; // 16 bytes for Complex128 (2 * Float64)
1582
1583 default:
1584 throw new ArgumentException("Unsupported NpyDataType", nameof(type));
1585 }
1586 }

◆ GetNpyTypeEnum()

static NpyDataType BioLib.NumPy.GetNpyTypeEnum ( string type)
static
1222 {
1223 switch (type)
1224 {
1225 case "|u1":
1226 return NpyDataType.UInt8;
1227 case "|i1":
1228 return NpyDataType.Int8;
1229 case "|u2":
1230 return NpyDataType.UInt16;
1231 case "|i2":
1232 return NpyDataType.Int16;
1233 case "|u4":
1234 return NpyDataType.UInt32;
1235 case "|i4":
1236 return NpyDataType.Int32;
1237 case "|u8":
1238 return NpyDataType.UInt64;
1239 case "|i8":
1240 return NpyDataType.Int64;
1241 case "|f2":
1242 return NpyDataType.Float16;
1243 case "|f4":
1244 return NpyDataType.Float32;
1245 case "|f8":
1246 return NpyDataType.Float64;
1247 case "|c8":
1248 return NpyDataType.Complex64;
1249 case "|c16":
1250 return NpyDataType.Complex128;
1251 case "<f4":
1252 return NpyDataType.Float32;
1253 case "<i4":
1254 return NpyDataType.Int32;
1255 default:
1256 throw new ArgumentException("Unsupported numpy type string", nameof(type));
1257 }
1258 }

◆ GetNpyTypeString()

static string BioLib.NumPy.GetNpyTypeString ( NpyDataType type)
static
1188 {
1189 switch (type)
1190 {
1191 case NpyDataType.UInt8:
1192 return "|u1";
1193 case NpyDataType.Int8:
1194 return "|i1";
1195 case NpyDataType.UInt16:
1196 return "|u2";
1197 case NpyDataType.Int16:
1198 return "|i2";
1199 case NpyDataType.UInt32:
1200 return "|u4";
1201 case NpyDataType.Int32:
1202 return "|i4";
1203 case NpyDataType.UInt64:
1204 return "|u8";
1205 case NpyDataType.Int64:
1206 return "|i8";
1207 case NpyDataType.Float16:
1208 return "|f2";
1209 case NpyDataType.Float32:
1210 return "|f4";
1211 case NpyDataType.Float64:
1212 return "|f8";
1213 case NpyDataType.Complex64:
1214 return "|c8";
1215 case NpyDataType.Complex128:
1216 return "|c16";
1217 default:
1218 throw new ArgumentException("Unsupported NpyDataType", nameof(type));
1219 }
1220 }

◆ ReadNpyFile()

static Array BioLib.NumPy.ReadNpyFile ( string filePath)
static
1388 {
1389 using (var reader = new BinaryReader(File.Open(filePath, FileMode.Open)))
1390 {
1391 // Verify .npy magic string
1392 byte[] magic = reader.ReadBytes(6);
1393 string magicString = Encoding.ASCII.GetString(magic);
1394 if (magicString != "?NUMPY")
1395 {
1396 throw new InvalidOperationException("Invalid .npy file.");
1397 }
1398
1399 // Skip the version information (2 bytes)
1400 reader.BaseStream.Seek(2, SeekOrigin.Current);
1401
1402 // Read the header length (2 bytes)
1403 byte[] headerLengthBytes = reader.ReadBytes(2);
1404 int headerLength = BitConverter.ToInt16(headerLengthBytes, 0);
1405
1406 // Read the header bytes
1407 byte[] headerBytes = reader.ReadBytes(headerLength);
1408 string headerString = Encoding.ASCII.GetString(headerBytes).Replace("True", "true").Replace("False", "false").Replace("(", "[").Replace(")", "]");
1409
1410 // Configure Json.NET to handle camel case
1411 var settings = new JsonSerializerSettings
1412 {
1413 ContractResolver = new CamelCasePropertyNamesContractResolver()
1414 };
1415
1416 // Deserialize the JSON string into an object of type NpyHeader
1417 NpyHeader header = JsonConvert.DeserializeObject<NpyHeader>(headerString, settings);
1418 var shape = header.shape;
1419 var dtype = header.descr;
1420 NpyDataType type = GetNpyTypeEnum(dtype);
1421
1422 // Calculate the total number of elements in the array
1423 int totalElements = shape.Aggregate(1, (acc, dim) => acc * dim); // Multiply all dimensions
1424
1425 // Calculate the data size based on the number of elements and element size
1426 int elementSize = GetElementSize(type);
1427 int dataSize = totalElements * elementSize;
1428
1429 // Read the data bytes
1430 byte[] dataBytes = reader.ReadBytes(dataSize);
1431
1432 // Convert the byte array to the proper data type array
1433 Array data = null;
1434 switch (type)
1435 {
1436 case NpyDataType.UInt8:
1437 data = new byte[dataBytes.Length];
1438 Buffer.BlockCopy(dataBytes, 0, data, 0, dataBytes.Length);
1439 break;
1440
1441 case NpyDataType.Int8:
1442 data = new sbyte[dataBytes.Length];
1443 Buffer.BlockCopy(dataBytes, 0, data, 0, dataBytes.Length);
1444 break;
1445
1446 case NpyDataType.UInt16:
1447 data = new ushort[totalElements]; // Using totalElements for multidimensional support
1448 for (int i = 0; i < data.Length; i++)
1449 {
1450 data.SetValue(BitConverter.ToUInt16(dataBytes, i * 2), i);
1451 }
1452 break;
1453
1454 case NpyDataType.Int16:
1455 data = new short[totalElements];
1456 for (int i = 0; i < data.Length; i++)
1457 {
1458 data.SetValue(BitConverter.ToInt16(dataBytes, i * 2), i);
1459 }
1460 break;
1461
1462 case NpyDataType.UInt32:
1463 data = new uint[totalElements];
1464 for (int i = 0; i < data.Length; i++)
1465 {
1466 data.SetValue(BitConverter.ToUInt32(dataBytes, i * 4), i);
1467 }
1468 break;
1469
1470 case NpyDataType.Int32:
1471 data = new int[totalElements];
1472 for (int i = 0; i < data.Length; i++)
1473 {
1474 data.SetValue(BitConverter.ToInt32(dataBytes, i * 4), i);
1475 }
1476 break;
1477
1478 case NpyDataType.UInt64:
1479 data = new ulong[totalElements];
1480 for (int i = 0; i < data.Length; i++)
1481 {
1482 data.SetValue(BitConverter.ToUInt64(dataBytes, i * 8), i);
1483 }
1484 break;
1485
1486 case NpyDataType.Int64:
1487 data = new long[totalElements];
1488 for (int i = 0; i < data.Length; i++)
1489 {
1490 data.SetValue(BitConverter.ToInt64(dataBytes, i * 8), i);
1491 }
1492 break;
1493
1494 case NpyDataType.Float16:
1495 // Convert each 2-byte segment to Float16 (not directly supported by BitConverter)
1496 // You'll need a custom method to handle Float16 conversion
1497 break;
1498
1499 case NpyDataType.Float32:
1500 data = new float[totalElements];
1501 for (int i = 0; i < data.Length; i++)
1502 {
1503 data.SetValue(BitConverter.ToSingle(dataBytes, i * 4), i);
1504 }
1505 break;
1506
1507 case NpyDataType.Float64:
1508 data = new double[totalElements];
1509 for (int i = 0; i < data.Length; i++)
1510 {
1511 data.SetValue(BitConverter.ToDouble(dataBytes, i * 8), i);
1512 }
1513 break;
1514
1515 case NpyDataType.Complex64:
1516 data = new (float, float)[totalElements];
1517 for (int i = 0; i < data.Length; i++)
1518 {
1519 var real = BitConverter.ToSingle(dataBytes, i * 8);
1520 var imaginary = BitConverter.ToSingle(dataBytes, i * 8 + 4);
1521 data.SetValue((real, imaginary), i);
1522 }
1523 break;
1524
1525 case NpyDataType.Complex128:
1526 data = new (double, double)[totalElements];
1527 for (int i = 0; i < data.Length; i++)
1528 {
1529 var real = BitConverter.ToDouble(dataBytes, i * 16);
1530 var imaginary = BitConverter.ToDouble(dataBytes, i * 16 + 8);
1531 data.SetValue((real, imaginary), i);
1532 }
1533 break;
1534
1535 default:
1536 throw new ArgumentException("Unsupported NpyDataType", nameof(type));
1537 }
1538
1539 return (shape, type, data);
1540 }
1541 }
static int GetElementSize(NpyDataType type)
Helper function to get the size of the elements based on dtype.
Definition Bio.cs:1548

◆ SaveNumPy()

static void BioLib.NumPy.SaveNumPy ( BioImage b,
string file )
static
1271 {
1272 float[] fs = new float[b.SizeT * b.SizeZ * b.SizeC * b.SizeX * b.SizeY];
1273 // Fill the flattened array
1274 int index = 0;
1275 for (int t = 0; t < b.SizeT; t++)
1276 {
1277 for (int z = 0; z < b.SizeZ; z++)
1278 {
1279 for (int c = 0; c < b.SizeC; c++)
1280 {
1281 for (int y = 0; y < b.SizeY; y++)
1282 {
1283 for (int x = 0; x < b.SizeX; x++)
1284 {
1285 fs[index++] = b.Buffers[b.Coords[z, c, t]].GetValue(x, y);
1286 }
1287 }
1288 }
1289 }
1290 }
1291 SaveFloatArrayAsNpy(file, fs, new int[] { b.SizeT, b.SizeC, b.SizeZ, b.SizeX, b.SizeY });
1292 }

The documentation for this class was generated from the following file: