BioLib  3.9.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
1156 {
1157 // Integer types
1158 UInt8 = 1, // |u1
1159 Int8 = 2, // |i1
1160 UInt16 = 3, // |u2
1161 Int16 = 4, // |i2
1162 UInt32 = 5, // |u4
1163 Int32 = 6, // |i4
1164 UInt64 = 7, // |u8
1165 Int64 = 8, // |i8
1166
1167 // Floating point types
1168 Float16 = 9, // |f2
1169 Float32 = 10, // |f4
1170 Float64 = 11, // |f8
1171
1172 // Complex number types (optional depending on your use case)
1173 Complex64 = 12, // |c8
1174 Complex128 = 13 // |c16
1175 }

Member Function Documentation

◆ ConvertBytesToTypedArray()

static Array BioLib.NumPy.ConvertBytesToTypedArray ( byte[] data,
NpyDataType dataType )
static
1671 {
1672 switch (dataType)
1673 {
1674 case NpyDataType.UInt8:
1675 return ConvertByteArrayToUInt8(data);
1676 case NpyDataType.Int8:
1677 return ConvertByteArrayToInt8(data);
1678 case NpyDataType.UInt16:
1679 return ConvertByteArrayToUInt16(data);
1680 case NpyDataType.Int16:
1681 return ConvertByteArrayToInt16(data);
1682 case NpyDataType.UInt32:
1683 return ConvertByteArrayToUInt32(data);
1684 case NpyDataType.Int32:
1685 return ConvertByteArrayToInt32(data);
1686 case NpyDataType.UInt64:
1687 return ConvertByteArrayToUInt64(data);
1688 case NpyDataType.Int64:
1689 return ConvertByteArrayToInt64(data);
1690 case NpyDataType.Float16:
1691 return ConvertByteArrayToFloat16(data);
1692 case NpyDataType.Float32:
1693 return ConvertByteArrayToFloat32(data);
1694 case NpyDataType.Float64:
1695 return ConvertByteArrayToFloat64(data);
1696 case NpyDataType.Complex64:
1697 return ConvertByteArrayToComplex64(data);
1698 case NpyDataType.Complex128:
1699 return ConvertByteArrayToComplex128(data);
1700 default:
1701 throw new ArgumentException("Unsupported data type", nameof(dataType));
1702 }
1703 }

◆ ConvertJaggedArray< T >()

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

◆ 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.
1338 {
1339 if (flatArray.Length != shape.Aggregate(1, (a, b) => a * b))
1340 throw new ArgumentException("The shape does not match the length of the flat array.");
1341
1342 var result = (Array)Array.CreateInstance(typeof(T), shape);
1343
1344 int[] indices = new int[shape.Length];
1345 for (int i = 0; i < flatArray.Length; i++)
1346 {
1347 // Compute the multi-dimensional indices
1348 int offset = i;
1349 for (int j = shape.Length - 1; j >= 0; j--)
1350 {
1351 indices[j] = offset % shape[j];
1352 offset /= shape[j];
1353 }
1354
1355 // Set the value in the multi-dimensional array
1356 result.SetValue(flatArray.GetValue(i), indices);
1357 }
1358
1359 return (TArray)(object)result;
1360 }

◆ CreateJaggedArray< T >()

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

◆ GetElementSize()

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

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

Parameters
dtype
Returns
1538 {
1539 switch (type)
1540 {
1541 case NpyDataType.UInt8:
1542 case NpyDataType.Int8:
1543 return 1; // 1 byte for UInt8 and Int8
1544
1545 case NpyDataType.UInt16:
1546 case NpyDataType.Int16:
1547 return 2; // 2 bytes for UInt16 and Int16
1548
1549 case NpyDataType.UInt32:
1550 case NpyDataType.Int32:
1551 return 4; // 4 bytes for UInt32 and Int32
1552
1553 case NpyDataType.UInt64:
1554 case NpyDataType.Int64:
1555 return 8; // 8 bytes for UInt64 and Int64
1556
1557 case NpyDataType.Float16:
1558 return 2; // 2 bytes for Float16
1559
1560 case NpyDataType.Float32:
1561 return 4; // 4 bytes for Float32
1562
1563 case NpyDataType.Float64:
1564 return 8; // 8 bytes for Float64
1565
1566 case NpyDataType.Complex64:
1567 return 8; // 8 bytes for Complex64 (2 * Float32)
1568
1569 case NpyDataType.Complex128:
1570 return 16; // 16 bytes for Complex128 (2 * Float64)
1571
1572 default:
1573 throw new ArgumentException("Unsupported NpyDataType", nameof(type));
1574 }
1575 }

◆ GetNpyTypeEnum()

static NpyDataType BioLib.NumPy.GetNpyTypeEnum ( string type)
static
1211 {
1212 switch (type)
1213 {
1214 case "|u1":
1215 return NpyDataType.UInt8;
1216 case "|i1":
1217 return NpyDataType.Int8;
1218 case "|u2":
1219 return NpyDataType.UInt16;
1220 case "|i2":
1221 return NpyDataType.Int16;
1222 case "|u4":
1223 return NpyDataType.UInt32;
1224 case "|i4":
1225 return NpyDataType.Int32;
1226 case "|u8":
1227 return NpyDataType.UInt64;
1228 case "|i8":
1229 return NpyDataType.Int64;
1230 case "|f2":
1231 return NpyDataType.Float16;
1232 case "|f4":
1233 return NpyDataType.Float32;
1234 case "|f8":
1235 return NpyDataType.Float64;
1236 case "|c8":
1237 return NpyDataType.Complex64;
1238 case "|c16":
1239 return NpyDataType.Complex128;
1240 case "<f4":
1241 return NpyDataType.Float32;
1242 case "<i4":
1243 return NpyDataType.Int32;
1244 default:
1245 throw new ArgumentException("Unsupported numpy type string", nameof(type));
1246 }
1247 }

◆ GetNpyTypeString()

static string BioLib.NumPy.GetNpyTypeString ( NpyDataType type)
static
1177 {
1178 switch (type)
1179 {
1180 case NpyDataType.UInt8:
1181 return "|u1";
1182 case NpyDataType.Int8:
1183 return "|i1";
1184 case NpyDataType.UInt16:
1185 return "|u2";
1186 case NpyDataType.Int16:
1187 return "|i2";
1188 case NpyDataType.UInt32:
1189 return "|u4";
1190 case NpyDataType.Int32:
1191 return "|i4";
1192 case NpyDataType.UInt64:
1193 return "|u8";
1194 case NpyDataType.Int64:
1195 return "|i8";
1196 case NpyDataType.Float16:
1197 return "|f2";
1198 case NpyDataType.Float32:
1199 return "|f4";
1200 case NpyDataType.Float64:
1201 return "|f8";
1202 case NpyDataType.Complex64:
1203 return "|c8";
1204 case NpyDataType.Complex128:
1205 return "|c16";
1206 default:
1207 throw new ArgumentException("Unsupported NpyDataType", nameof(type));
1208 }
1209 }

◆ ReadNpyFile()

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

◆ SaveNumPy()

static void BioLib.NumPy.SaveNumPy ( BioImage b,
string file )
static
1260 {
1261 float[] fs = new float[b.SizeT * b.SizeZ * b.SizeC * b.SizeX * b.SizeY];
1262 // Fill the flattened array
1263 int index = 0;
1264 for (int t = 0; t < b.SizeT; t++)
1265 {
1266 for (int z = 0; z < b.SizeZ; z++)
1267 {
1268 for (int c = 0; c < b.SizeC; c++)
1269 {
1270 for (int y = 0; y < b.SizeY; y++)
1271 {
1272 for (int x = 0; x < b.SizeX; x++)
1273 {
1274 fs[index++] = b.Buffers[b.Coords[z, c, t]].GetValue(x, y);
1275 }
1276 }
1277 }
1278 }
1279 }
1280 SaveFloatArrayAsNpy(file, fs, new int[] { b.SizeT, b.SizeC, b.SizeZ, b.SizeX, b.SizeY });
1281 }

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