BioLib  3.7.0
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
1144 {
1145 // Integer types
1146 UInt8 = 1, // |u1
1147 Int8 = 2, // |i1
1148 UInt16 = 3, // |u2
1149 Int16 = 4, // |i2
1150 UInt32 = 5, // |u4
1151 Int32 = 6, // |i4
1152 UInt64 = 7, // |u8
1153 Int64 = 8, // |i8
1154
1155 // Floating point types
1156 Float16 = 9, // |f2
1157 Float32 = 10, // |f4
1158 Float64 = 11, // |f8
1159
1160 // Complex number types (optional depending on your use case)
1161 Complex64 = 12, // |c8
1162 Complex128 = 13 // |c16
1163 }

Member Function Documentation

◆ ConvertBytesToTypedArray()

static Array BioLib.NumPy.ConvertBytesToTypedArray ( byte[] data,
NpyDataType dataType )
static
1659 {
1660 switch (dataType)
1661 {
1662 case NpyDataType.UInt8:
1663 return ConvertByteArrayToUInt8(data);
1664 case NpyDataType.Int8:
1665 return ConvertByteArrayToInt8(data);
1666 case NpyDataType.UInt16:
1667 return ConvertByteArrayToUInt16(data);
1668 case NpyDataType.Int16:
1669 return ConvertByteArrayToInt16(data);
1670 case NpyDataType.UInt32:
1671 return ConvertByteArrayToUInt32(data);
1672 case NpyDataType.Int32:
1673 return ConvertByteArrayToInt32(data);
1674 case NpyDataType.UInt64:
1675 return ConvertByteArrayToUInt64(data);
1676 case NpyDataType.Int64:
1677 return ConvertByteArrayToInt64(data);
1678 case NpyDataType.Float16:
1679 return ConvertByteArrayToFloat16(data);
1680 case NpyDataType.Float32:
1681 return ConvertByteArrayToFloat32(data);
1682 case NpyDataType.Float64:
1683 return ConvertByteArrayToFloat64(data);
1684 case NpyDataType.Complex64:
1685 return ConvertByteArrayToComplex64(data);
1686 case NpyDataType.Complex128:
1687 return ConvertByteArrayToComplex128(data);
1688 default:
1689 throw new ArgumentException("Unsupported data type", nameof(dataType));
1690 }
1691 }

◆ ConvertJaggedArray< T >()

static T BioLib.NumPy.ConvertJaggedArray< T > ( Array jaggedArray)
static
1566 {
1567 // Ensure the provided array is of the correct jagged array type
1568 if (jaggedArray is int[][] jagged)
1569 {
1570 int rows = jagged.Length;
1571 int cols = jagged[0].Length;
1572
1573 // Create an instance of the desired 2D array using reflection
1574 T result = (T)Activator.CreateInstance(typeof(T), new object[] { rows, cols });
1575
1576 // Copy values from jagged array to the newly created 2D array
1577 for (int i = 0; i < rows; i++)
1578 {
1579 for (int j = 0; j < cols; j++)
1580 {
1581 // Use reflection to set the value in the result array
1582 var element = result.GetType().GetElementType();
1583 result.GetType().GetMethod("SetValue").Invoke(result, new object[] { jagged[i][j], i, j });
1584 }
1585 }
1586
1587 return result;
1588 }
1589
1590 throw new InvalidCastException("The input array is not of the expected type.");
1591 }

◆ 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.
1326 {
1327 if (flatArray.Length != shape.Aggregate(1, (a, b) => a * b))
1328 throw new ArgumentException("The shape does not match the length of the flat array.");
1329
1330 var result = (Array)Array.CreateInstance(typeof(T), shape);
1331
1332 int[] indices = new int[shape.Length];
1333 for (int i = 0; i < flatArray.Length; i++)
1334 {
1335 // Compute the multi-dimensional indices
1336 int offset = i;
1337 for (int j = shape.Length - 1; j >= 0; j--)
1338 {
1339 indices[j] = offset % shape[j];
1340 offset /= shape[j];
1341 }
1342
1343 // Set the value in the multi-dimensional array
1344 result.SetValue(flatArray.GetValue(i), indices);
1345 }
1346
1347 return (TArray)(object)result;
1348 }

◆ CreateJaggedArray< T >()

static T BioLib.NumPy.CreateJaggedArray< T > ( int[] shape,
T[] data,
int dimension )
static
Type Constraints
T :struct 
1593 : struct
1594 {
1595 // Base case: if we reached the last dimension, return the data array for that dimension
1596 if (dimension == shape.Length - 1)
1597 {
1598 // Create a 2D array for the last dimension
1599 T[,] array = (T[,])Activator.CreateInstance(typeof(T[,]), shape[dimension], data.Length / shape[dimension]);
1600 Array.Copy(data, array, data.Length); // Copy data into the array
1601 return (T)(object)array; // Cast to T (we will handle this later)
1602 }
1603
1604 // Recursive case: create jagged array for higher dimensions
1605 int subDimensionSize = shape[dimension + 1];
1606 int firstDimLength = shape[dimension];
1607
1608 // Create a jagged array for the current dimension
1609 Array jaggedArray = Array.CreateInstance(typeof(Array), shape[dimension]);
1610
1611 int index = 0;
1612 for (int i = 0; i < firstDimLength; i++)
1613 {
1614 // Recursively create the sub-arrays
1615 var subArray = CreateJaggedArray(shape, data.Skip(index).Take(subDimensionSize).ToArray(), dimension + 1);
1616 jaggedArray.SetValue(subArray, i); // Set the sub-array at index
1617 index += subDimensionSize;
1618 }
1619
1620 // Return the jagged array
1621 return (T)System.Convert.ChangeType(jaggedArray, typeof(T)); // Use Convert.ChangeType to cast System.Array to T
1622 }

◆ GetElementSize()

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

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

Parameters
dtype
Returns
1526 {
1527 switch (type)
1528 {
1529 case NpyDataType.UInt8:
1530 case NpyDataType.Int8:
1531 return 1; // 1 byte for UInt8 and Int8
1532
1533 case NpyDataType.UInt16:
1534 case NpyDataType.Int16:
1535 return 2; // 2 bytes for UInt16 and Int16
1536
1537 case NpyDataType.UInt32:
1538 case NpyDataType.Int32:
1539 return 4; // 4 bytes for UInt32 and Int32
1540
1541 case NpyDataType.UInt64:
1542 case NpyDataType.Int64:
1543 return 8; // 8 bytes for UInt64 and Int64
1544
1545 case NpyDataType.Float16:
1546 return 2; // 2 bytes for Float16
1547
1548 case NpyDataType.Float32:
1549 return 4; // 4 bytes for Float32
1550
1551 case NpyDataType.Float64:
1552 return 8; // 8 bytes for Float64
1553
1554 case NpyDataType.Complex64:
1555 return 8; // 8 bytes for Complex64 (2 * Float32)
1556
1557 case NpyDataType.Complex128:
1558 return 16; // 16 bytes for Complex128 (2 * Float64)
1559
1560 default:
1561 throw new ArgumentException("Unsupported NpyDataType", nameof(type));
1562 }
1563 }

◆ GetNpyTypeEnum()

static NpyDataType BioLib.NumPy.GetNpyTypeEnum ( string type)
static
1199 {
1200 switch (type)
1201 {
1202 case "|u1":
1203 return NpyDataType.UInt8;
1204 case "|i1":
1205 return NpyDataType.Int8;
1206 case "|u2":
1207 return NpyDataType.UInt16;
1208 case "|i2":
1209 return NpyDataType.Int16;
1210 case "|u4":
1211 return NpyDataType.UInt32;
1212 case "|i4":
1213 return NpyDataType.Int32;
1214 case "|u8":
1215 return NpyDataType.UInt64;
1216 case "|i8":
1217 return NpyDataType.Int64;
1218 case "|f2":
1219 return NpyDataType.Float16;
1220 case "|f4":
1221 return NpyDataType.Float32;
1222 case "|f8":
1223 return NpyDataType.Float64;
1224 case "|c8":
1225 return NpyDataType.Complex64;
1226 case "|c16":
1227 return NpyDataType.Complex128;
1228 case "<f4":
1229 return NpyDataType.Float32;
1230 case "<i4":
1231 return NpyDataType.Int32;
1232 default:
1233 throw new ArgumentException("Unsupported numpy type string", nameof(type));
1234 }
1235 }

◆ GetNpyTypeString()

static string BioLib.NumPy.GetNpyTypeString ( NpyDataType type)
static
1165 {
1166 switch (type)
1167 {
1168 case NpyDataType.UInt8:
1169 return "|u1";
1170 case NpyDataType.Int8:
1171 return "|i1";
1172 case NpyDataType.UInt16:
1173 return "|u2";
1174 case NpyDataType.Int16:
1175 return "|i2";
1176 case NpyDataType.UInt32:
1177 return "|u4";
1178 case NpyDataType.Int32:
1179 return "|i4";
1180 case NpyDataType.UInt64:
1181 return "|u8";
1182 case NpyDataType.Int64:
1183 return "|i8";
1184 case NpyDataType.Float16:
1185 return "|f2";
1186 case NpyDataType.Float32:
1187 return "|f4";
1188 case NpyDataType.Float64:
1189 return "|f8";
1190 case NpyDataType.Complex64:
1191 return "|c8";
1192 case NpyDataType.Complex128:
1193 return "|c16";
1194 default:
1195 throw new ArgumentException("Unsupported NpyDataType", nameof(type));
1196 }
1197 }

◆ ReadNpyFile()

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

◆ SaveNumPy()

static void BioLib.NumPy.SaveNumPy ( BioImage b,
string file )
static
1248 {
1249 float[] fs = new float[b.SizeT * b.SizeZ * b.SizeC * b.SizeX * b.SizeY];
1250 // Fill the flattened array
1251 int index = 0;
1252 for (int t = 0; t < b.SizeT; t++)
1253 {
1254 for (int z = 0; z < b.SizeZ; z++)
1255 {
1256 for (int c = 0; c < b.SizeC; c++)
1257 {
1258 for (int y = 0; y < b.SizeY; y++)
1259 {
1260 for (int x = 0; x < b.SizeX; x++)
1261 {
1262 fs[index++] = b.Buffers[b.Coords[z, c, t]].GetValue(x, y);
1263 }
1264 }
1265 }
1266 }
1267 }
1268 SaveFloatArrayAsNpy(file, fs, new int[] { b.SizeT, b.SizeC, b.SizeZ, b.SizeX, b.SizeY });
1269 }

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