/Source/IO/ImageIO.cs

https://github.com/dajuric/dot-imaging · C# · 626 lines · 285 code · 76 blank · 265 comment · 6 complexity · b07d2b53d771fa96b130ac684e73defc MD5 · raw file

  1. #region Licence and Terms
  2. // DotImaging Framework
  3. // https://github.com/dajuric/dot-imaging
  4. //
  5. // Copyright © Darko Jurić, 2014-2019
  6. // darko.juric2@gmail.com
  7. //
  8. // Licensed under the Apache License, Version 2.0 (the "License");
  9. // you may not use this file except in compliance with the License.
  10. // You may obtain a copy of the License at
  11. //
  12. // http://www.apache.org/licenses/LICENSE-2.0
  13. //
  14. // Unless required by applicable law or agreed to in writing, software
  15. // distributed under the License is distributed on an "AS IS" BASIS,
  16. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. // See the License for the specific language governing permissions and
  18. // limitations under the License.
  19. //
  20. #endregion
  21. using System;
  22. namespace DotImaging
  23. {
  24. /// <summary>
  25. /// Provides methods for image saving and loading
  26. /// </summary>
  27. public static class ImageIO
  28. {
  29. #region Load (file)
  30. private unsafe static IImage load(string fileName, ImageLoadType imageLoadType)
  31. {
  32. var iplImagePtr = CvInvoke.cvLoadImage(fileName, imageLoadType);
  33. var image = (*iplImagePtr).AsImage((_) =>
  34. {
  35. if (iplImagePtr == null) return;
  36. CvInvoke.cvReleaseImage(ref iplImagePtr);
  37. });
  38. return image;
  39. }
  40. /// <summary>
  41. /// Loads an image with the specified path and name as it is.
  42. /// </summary>
  43. /// <param name="fileName">Image file name.</param>
  44. /// <returns>Image.</returns>
  45. public unsafe static IImage LoadUnchanged(this string fileName)
  46. {
  47. return load(fileName, ImageLoadType.Unchanged);
  48. }
  49. /// <summary>
  50. /// Loads an image with the specified path and name and performs and RGB conversion.
  51. /// </summary>
  52. /// <param name="fileName">Image filename.</param>
  53. /// <returns>Image.</returns>
  54. public unsafe static Bgr<byte>[,] LoadColor(this string fileName)
  55. {
  56. Bgr<byte>[,] im = null;
  57. using (var uIm = load(fileName, ImageLoadType.Color) as Image<Bgr<byte>>)
  58. im = uIm.Clone();
  59. return im;
  60. }
  61. /// <summary>
  62. /// Loads an image with the specified path and name and performs and gray conversion.
  63. /// </summary>
  64. /// <param name="fileName">Image filename.</param>
  65. /// <returns>Image.</returns>
  66. public unsafe static Gray<byte>[,] LoadGray(this string fileName)
  67. {
  68. Gray<byte>[,] im = null;
  69. using (var uIm = load(fileName, ImageLoadType.Grayscale) as Image<Gray<byte>>)
  70. im = uIm.Clone();
  71. return im;
  72. }
  73. #endregion
  74. #region Save (file)
  75. /// <summary>
  76. /// Saves the provided image. If the image has non-supported color or depth false value is returned.
  77. /// </summary>
  78. /// <param name="image">Image to save.</param>
  79. /// <param name="fileName">Filename.</param>
  80. /// <returns>True if the image is saved, false otherwise.</returns>
  81. public unsafe static bool TrySave(IImage image, string fileName)
  82. {
  83. IplImage iplImage = default(IplImage);
  84. try
  85. {
  86. iplImage = image.AsCvIplImage();
  87. }
  88. catch
  89. {
  90. return false;
  91. }
  92. CvInvoke.cvSaveImage(fileName, &iplImage, IntPtr.Zero);
  93. return true;
  94. }
  95. /// <summary>
  96. /// Saves the specified image.
  97. /// </summary>
  98. /// <typeparam name="TColor">Image color.</typeparam>
  99. /// <param name="image">Image to save.</param>
  100. /// <param name="fileName">Image filename.</param>
  101. private unsafe static void Save<TColor>(this Image<TColor> image, string fileName)
  102. where TColor : unmanaged, IColor
  103. {
  104. var iplImage = image.AsCvIplImage();
  105. CvInvoke.cvSaveImage(fileName, &iplImage, IntPtr.Zero);
  106. }
  107. /// <summary>
  108. /// Saves the specified image.
  109. /// </summary>
  110. /// <typeparam name="TColor">Image color.</typeparam>
  111. /// <param name="image">Image to save.</param>
  112. /// <param name="fileName">Image filename.</param>
  113. private unsafe static void Save<TColor>(this TColor[,] image, string fileName)
  114. where TColor: unmanaged, IColor
  115. {
  116. using (var img = image.Lock())
  117. {
  118. var iplImage = img.AsCvIplImage();
  119. CvInvoke.cvSaveImage(fileName, &iplImage, IntPtr.Zero);
  120. }
  121. }
  122. #region Save-gray
  123. /// <summary>
  124. /// Saves the specified image.
  125. /// </summary>
  126. /// <param name="image">Image to save.</param>
  127. /// <param name="fileName">Image filename.</param>
  128. public static void Save(this Gray<byte>[,] image, string fileName)
  129. {
  130. image.Save<Gray<byte>>(fileName);
  131. }
  132. /// <summary>
  133. /// Saves the specified image.
  134. /// </summary>
  135. /// <param name="image">Image to save.</param>
  136. /// <param name="fileName">Image filename.</param>
  137. public static void Save(this Gray<sbyte>[,] image, string fileName)
  138. {
  139. image.Save<Gray<sbyte>>(fileName);
  140. }
  141. /// <summary>
  142. /// Saves the specified image.
  143. /// </summary>
  144. /// <param name="image">Image to save.</param>
  145. /// <param name="fileName">Image filename.</param>
  146. public static void Save(this Gray<short>[,] image, string fileName)
  147. {
  148. image.Save<Gray<short>>(fileName);
  149. }
  150. /// <summary>
  151. /// Saves the specified image.
  152. /// </summary>
  153. /// <param name="image">Image to save.</param>
  154. /// <param name="fileName">Image filename.</param>
  155. public static void Save(this Gray<ushort>[,] image, string fileName)
  156. {
  157. image.Save<Gray<ushort>>(fileName);
  158. }
  159. /// <summary>
  160. /// Saves the specified image.
  161. /// </summary>
  162. /// <param name="image">Image to save.</param>
  163. /// <param name="fileName">Image filename.</param>
  164. public static void Save(this Gray<int>[,] image, string fileName)
  165. {
  166. image.Save<Gray<int>>(fileName);
  167. }
  168. /// <summary>
  169. /// Saves the specified image.
  170. /// </summary>
  171. /// <param name="image">Image to save.</param>
  172. /// <param name="fileName">Image filename.</param>
  173. public static void Save(this Gray<float>[,] image, string fileName)
  174. {
  175. image.Save<Gray<float>>(fileName);
  176. }
  177. /// <summary>
  178. /// Saves the specified image.
  179. /// </summary>
  180. /// <param name="image">Image to save.</param>
  181. /// <param name="fileName">Image filename.</param>
  182. public static void Save(this Gray<double>[,] image, string fileName)
  183. {
  184. image.Save<Gray<double>>(fileName);
  185. }
  186. #endregion
  187. #region Save-bgr
  188. /// <summary>
  189. /// Saves the specified image.
  190. /// </summary>
  191. /// <param name="image">Image to save.</param>
  192. /// <param name="fileName">Image filename.</param>
  193. public static void Save(this Bgr<byte>[,] image, string fileName)
  194. {
  195. image.Save<Bgr<byte>>(fileName);
  196. }
  197. /// <summary>
  198. /// Saves the specified image.
  199. /// </summary>
  200. /// <param name="image">Image to save.</param>
  201. /// <param name="fileName">Image filename.</param>
  202. public static void Save(this Bgr<sbyte>[,] image, string fileName)
  203. {
  204. image.Save<Bgr<sbyte>>(fileName);
  205. }
  206. /// <summary>
  207. /// Saves the specified image.
  208. /// </summary>
  209. /// <param name="image">Image to save.</param>
  210. /// <param name="fileName">Image filename.</param>
  211. public static void Save(this Bgr<short>[,] image, string fileName)
  212. {
  213. image.Save<Bgr<short>>(fileName);
  214. }
  215. /// <summary>
  216. /// Saves the specified image.
  217. /// </summary>
  218. /// <param name="image">Image to save.</param>
  219. /// <param name="fileName">Image filename.</param>
  220. public static void Save(this Bgr<ushort>[,] image, string fileName)
  221. {
  222. image.Save<Bgr<ushort>>(fileName);
  223. }
  224. /// <summary>
  225. /// Saves the specified image.
  226. /// </summary>
  227. /// <param name="image">Image to save.</param>
  228. /// <param name="fileName">Image filename.</param>
  229. public static void Save(this Bgr<int>[,] image, string fileName)
  230. {
  231. image.Save<Bgr<int>>(fileName);
  232. }
  233. /// <summary>
  234. /// Saves the specified image.
  235. /// </summary>
  236. /// <param name="image">Image to save.</param>
  237. /// <param name="fileName">Image filename.</param>
  238. public static void Save(this Bgr<float>[,] image, string fileName)
  239. {
  240. image.Save<Bgr<float>>(fileName);
  241. }
  242. /// <summary>
  243. /// Saves the specified image.
  244. /// </summary>
  245. /// <param name="image">Image to save.</param>
  246. /// <param name="fileName">Image filename.</param>
  247. public static void Save(this Bgr<double>[,] image, string fileName)
  248. {
  249. image.Save<Bgr<double>>(fileName);
  250. }
  251. #endregion
  252. #region Save-bgra
  253. /// <summary>
  254. /// Saves the specified image.
  255. /// </summary>
  256. /// <param name="image">Image to save.</param>
  257. /// <param name="fileName">Image filename.</param>
  258. public static void Save(this Bgra<byte>[,] image, string fileName)
  259. {
  260. image.Save<Bgra<byte>>(fileName);
  261. }
  262. /// <summary>
  263. /// Saves the specified image.
  264. /// </summary>
  265. /// <param name="image">Image to save.</param>
  266. /// <param name="fileName">Image filename.</param>
  267. public static void Save(this Bgra<sbyte>[,] image, string fileName)
  268. {
  269. image.Save<Bgra<sbyte>>(fileName);
  270. }
  271. /// <summary>
  272. /// Saves the specified image.
  273. /// </summary>
  274. /// <param name="image">Image to save.</param>
  275. /// <param name="fileName">Image filename.</param>
  276. public static void Save(this Bgra<short>[,] image, string fileName)
  277. {
  278. image.Save<Bgra<short>>(fileName);
  279. }
  280. /// <summary>
  281. /// Saves the specified image.
  282. /// </summary>
  283. /// <param name="image">Image to save.</param>
  284. /// <param name="fileName">Image filename.</param>
  285. public static void Save(this Bgra<ushort>[,] image, string fileName)
  286. {
  287. image.Save<Bgra<ushort>>(fileName);
  288. }
  289. /// <summary>
  290. /// Saves the specified image.
  291. /// </summary>
  292. /// <param name="image">Image to save.</param>
  293. /// <param name="fileName">Image filename.</param>
  294. public static void Save(this Bgra<int>[,] image, string fileName)
  295. {
  296. image.Save<Bgra<int>>(fileName);
  297. }
  298. /// <summary>
  299. /// Saves the specified image.
  300. /// </summary>
  301. /// <param name="image">Image to save.</param>
  302. /// <param name="fileName">Image filename.</param>
  303. public static void Save(this Bgra<float>[,] image, string fileName)
  304. {
  305. image.Save<Bgra<float>>(fileName);
  306. }
  307. /// <summary>
  308. /// Saves the specified image.
  309. /// </summary>
  310. /// <param name="image">Image to save.</param>
  311. /// <param name="fileName">Image filename.</param>
  312. public static void Save(this Bgra<double>[,] image, string fileName)
  313. {
  314. image.Save<Bgra<double>>(fileName);
  315. }
  316. #endregion
  317. #endregion
  318. #region Encode
  319. /// <summary>
  320. /// Encodes the specified image into the Jpeg byte array.
  321. /// </summary>
  322. /// <param name="image">Image to encode.</param>
  323. /// <param name="jpegQuality">Jpeg quality [0..100] where 100 is the highest quality.</param>
  324. /// <returns>Jpeg byte array.</returns>
  325. public static byte[] EncodeAsJpeg(this Gray<byte>[,] image, int jpegQuality = 95)
  326. {
  327. return encodeAsJpeg(image, jpegQuality);
  328. }
  329. /// <summary>
  330. /// Encodes the specified image into the Jpeg byte array.
  331. /// </summary>
  332. /// <param name="image">Image to encode.</param>
  333. /// <param name="jpegQuality">Jpeg quality [0..100] where 100 is the highest quality.</param>
  334. /// <returns>Jpeg byte array.</returns>
  335. public static byte[] EncodeAsJpeg(this Bgr<byte>[,] image, int jpegQuality = 95)
  336. {
  337. return encodeAsJpeg(image, jpegQuality);
  338. }
  339. /// <summary>
  340. /// Encodes the specified image into the Jpeg byte array.
  341. /// </summary>
  342. /// <param name="image">Image to encode.</param>
  343. /// <param name="jpegQuality">Jpeg quality [0..100] where 100 is the highest quality.</param>
  344. /// <returns>Jpeg byte array.</returns>
  345. public static byte[] EncodeAsJpeg(this Gray<ushort>[,] image, int jpegQuality = 95)
  346. {
  347. return encodeAsJpeg(image, jpegQuality);
  348. }
  349. /// <summary>
  350. /// Encodes the specified image into the Jpeg byte array.
  351. /// </summary>
  352. /// <param name="image">Image to encode.</param>
  353. /// <param name="jpegQuality">Jpeg quality [0..100] where 100 is the highest quality.</param>
  354. /// <returns>Jpeg byte array.</returns>
  355. public static byte[] EncodeAsJpeg(this Bgr<ushort>[,] image, int jpegQuality = 95)
  356. {
  357. return encodeAsJpeg(image, jpegQuality);
  358. }
  359. /// <summary>
  360. /// Encodes the specified image into the PNG byte array.
  361. /// </summary>
  362. /// <param name="image">Image to encode.</param>
  363. /// <param name="pngCompression">PNG compression level [0..9] where 9 is the highest compression.</param>
  364. /// <returns>PNG byte array.</returns>
  365. public static byte[] EncodeAsPng(this Gray<byte>[,] image, int pngCompression = 3)
  366. {
  367. return encodeAsPng(image, pngCompression);
  368. }
  369. /// <summary>
  370. /// Encodes the specified image into the PNG byte array.
  371. /// </summary>
  372. /// <param name="image">Image to encode.</param>
  373. /// <param name="pngCompression">PNG compression level [0..9] where 9 is the highest compression.</param>
  374. /// <returns>PNG byte array.</returns>
  375. public static byte[] EncodeAsPng(this Bgr<byte>[,] image, int pngCompression = 3)
  376. {
  377. return encodeAsPng(image, pngCompression);
  378. }
  379. /// <summary>
  380. /// Encodes the specified image into the PNG byte array.
  381. /// </summary>
  382. /// <param name="image">Image to encode.</param>
  383. /// <param name="pngCompression">PNG compression level [0..9] where 9 is the highest compression.</param>
  384. /// <returns>PNG byte array.</returns>
  385. public static byte[] EncodeAsPng(this Bgra<byte>[,] image, int pngCompression = 3)
  386. {
  387. return encodeAsPng(image, pngCompression);
  388. }
  389. /// <summary>
  390. /// Encodes the specified image into the PNG byte array.
  391. /// </summary>
  392. /// <param name="image">Image to encode.</param>
  393. /// <param name="pngCompression">PNG compression level [0..9] where 9 is the highest compression.</param>
  394. /// <returns>PNG byte array.</returns>
  395. public static byte[] EncodeAsPng(this Gray<ushort>[,] image, int pngCompression = 3)
  396. {
  397. return encodeAsPng(image, pngCompression);
  398. }
  399. /// <summary>
  400. /// Encodes the specified image into the PNG byte array.
  401. /// </summary>
  402. /// <param name="image">Image to encode.</param>
  403. /// <param name="pngCompression">PNG compression level [0..9] where 9 is the highest compression.</param>
  404. /// <returns>PNG byte array.</returns>
  405. public static byte[] EncodeAsPng(this Bgr<ushort>[,] image, int pngCompression = 3)
  406. {
  407. return encodeAsPng(image, pngCompression);
  408. }
  409. /// <summary>
  410. /// Encodes the specified image into the PNG byte array.
  411. /// </summary>
  412. /// <param name="image">Image to encode.</param>
  413. /// <param name="pngCompression">PNG compression level [0..9] where 9 is the highest compression.</param>
  414. /// <returns>PNG byte array.</returns>
  415. public static byte[] EncodeAsPng(this Bgra<ushort>[,] image, int pngCompression = 3)
  416. {
  417. return encodeAsPng(image, pngCompression);
  418. }
  419. /// <summary>
  420. /// Encodes the specified image into the specified image type byte array.
  421. /// </summary>
  422. /// <param name="image">Image to encode.</param>
  423. /// <param name="extension">Image type extension (.bmp, .png, .jpg)</param>
  424. /// <returns>Image type byte array.</returns>
  425. public static byte[] Encode(this Gray<byte>[,] image, string extension)
  426. {
  427. return encode(image, extension, null);
  428. }
  429. /// <summary>
  430. /// Encodes the specified image into the specified image type byte array.
  431. /// </summary>
  432. /// <param name="image">Image to encode.</param>
  433. /// <param name="extension">Image type extension (.bmp, .png, .jpg)</param>
  434. /// <returns>Image type byte array.</returns>
  435. public static byte[] Encode(this Bgr<byte>[,] image, string extension)
  436. {
  437. return encode(image, extension, null);
  438. }
  439. /// <summary>
  440. /// Encodes the specified image into the specified image type byte array.
  441. /// </summary>
  442. /// <param name="image">Image to encode.</param>
  443. /// <param name="extension">Image type extension (.bmp, .png, .jpg)</param>
  444. /// <returns>Image type byte array.</returns>
  445. public static byte[] Encode(this Bgra<byte>[,] image, string extension)
  446. {
  447. return encode(image, extension, null);
  448. }
  449. /// <summary>
  450. /// Encodes the specified image into the specified image type byte array.
  451. /// </summary>
  452. /// <param name="image">Image to encode.</param>
  453. /// <param name="extension">Image type extension (.bmp, .png, .jpg)</param>
  454. /// <returns>Image type byte array.</returns>
  455. public static byte[] Encode(this Gray<ushort>[,] image, string extension)
  456. {
  457. return encode(image, extension, null);
  458. }
  459. /// <summary>
  460. /// Encodes the specified image into the specified image type byte array.
  461. /// </summary>
  462. /// <param name="image">Image to encode.</param>
  463. /// <param name="extension">Image type extension (.bmp, .png, .jpg)</param>
  464. /// <returns>Image type byte array.</returns>
  465. public static byte[] Encode(this Bgr<ushort>[,] image, string extension)
  466. {
  467. return encode(image, extension, null);
  468. }
  469. /// <summary>
  470. /// Encodes the specified image into the specified image type byte array.
  471. /// </summary>
  472. /// <param name="image">Image to encode.</param>
  473. /// <param name="extension">Image type extension (.bmp, .png, .jpg)</param>
  474. /// <returns>Image type byte array.</returns>
  475. public static byte[] Encode(this Bgra<ushort>[,] image, string extension)
  476. {
  477. return encode(image, extension, null);
  478. }
  479. static byte[] encodeAsJpeg<TColor>(TColor[,] image, int jpegQuality = 95)
  480. where TColor : unmanaged, IColor
  481. {
  482. if (jpegQuality < 0 || jpegQuality > 100)
  483. throw new ArgumentOutOfRangeException("Jpeg quality must be in range: 0-100.");
  484. int[] parameters = new int[] { CvInvoke.CV_IMWRITE_JPEG_QUALITY, jpegQuality, 0 };
  485. return encode(image, ".jpg", parameters);
  486. }
  487. static byte[] encodeAsPng<TColor>(TColor[,] image, int pngCompression = 3)
  488. where TColor : unmanaged, IColor
  489. {
  490. if (pngCompression < 0 || pngCompression > 9)
  491. throw new ArgumentOutOfRangeException("Png compression must be in range: 0-9.");
  492. int[] parameters = new int[] { CvInvoke.CV_IMWRITE_PNG_COMPRESSION, pngCompression, 0 };
  493. return encode(image, ".png", parameters);
  494. }
  495. static unsafe byte[] encode<TColor>(TColor[,] image, string extension, int[] parameters)
  496. where TColor : unmanaged, IColor
  497. {
  498. CvMat* matEncoded; //a single-row image
  499. using (var uImg = image.Lock())
  500. {
  501. fixed (int* paramsPtr = parameters)
  502. {
  503. var mat = uImg.AsCvMat();
  504. matEncoded = CvInvoke.cvEncodeImage(extension, &mat, paramsPtr);
  505. }
  506. }
  507. byte[] imEncoded = new byte[matEncoded->Step * matEncoded->Height];
  508. fixed (byte* arrPtr = &imEncoded[0])
  509. {
  510. Copy.UnsafeCopy(matEncoded->ImageData, (IntPtr)arrPtr, imEncoded.Length);
  511. }
  512. CvInvoke.cvReleaseMat(ref matEncoded); //TODOD: check if this deferences the image
  513. return imEncoded;
  514. }
  515. #endregion
  516. #region Decode
  517. /// <summary>
  518. /// Decodes (and converts if necessary) an image as color image using the specified byte array.
  519. /// </summary>
  520. /// <param name="encodedImage">Encoded image.</param>
  521. /// <returns>Decoded image.</returns>
  522. public unsafe static Bgr<byte>[,] DecodeAsColorImage(this byte[] encodedImage)
  523. {
  524. return decodeImage<Bgr<byte>>(encodedImage, ImageLoadType.Color);
  525. }
  526. /// <summary>
  527. /// Decodes (and converts if necessary) an image as gray image using the specified byte array.
  528. /// </summary>
  529. /// <param name="encodedImage">Encoded image.</param>
  530. /// <returns>Decoded image.</returns>
  531. public unsafe static Gray<byte>[,] DecodeAsGrayImage(this byte[] encodedImage)
  532. {
  533. return decodeImage<Gray<byte>>(encodedImage, ImageLoadType.Grayscale);
  534. }
  535. unsafe static TColor[,] decodeImage<TColor>(byte[] encodedImage, ImageLoadType loadType)
  536. where TColor : unmanaged, IColor
  537. {
  538. CvMat* matDecoded;
  539. fixed (byte* encodedImPtr = encodedImage)
  540. {
  541. CvMat mat = CvMat.FromUserData((IntPtr)encodedImPtr, encodedImage.Length, 1, encodedImage.Length, CvMat.CvChannelDepth.CV_8U, 1);
  542. matDecoded = CvInvoke.cvDecodeImageM(&mat, ImageLoadType.Color);
  543. }
  544. var imDecoded = (*matDecoded).ToArray<TColor>();
  545. CvInvoke.cvReleaseMat(ref matDecoded);
  546. return imDecoded;
  547. }
  548. #endregion
  549. }
  550. }