Repository: dajuric/dot-imaging Branch: master Commit: 27d39aad31a5 Files: 91 Total size: 432.8 KB Directory structure: gitextract_pvk6qki_/ ├── .gitignore ├── Deploy/ │ ├── Licence.txt │ ├── Logo/ │ │ └── DotImaging.pptx │ └── Nuget/ │ └── Push.ps1 ├── Directory.Build.props ├── DotImaging.sln ├── README.md ├── Samples/ │ ├── Sample.Basic/ │ │ ├── Program.cs │ │ └── Sample.Basic.csproj │ ├── Sample.Capture/ │ │ ├── Program.cs │ │ └── Sample.Capture.csproj │ ├── Sample.CaptureAndRecord/ │ │ ├── Program.cs │ │ └── Sample.CaptureAndRecord.csproj │ ├── Sample.ImageExtractor/ │ │ ├── Program.cs │ │ └── Sample.ImageExtractor.csproj │ ├── Sample.Interop/ │ │ ├── Program.cs │ │ └── Sample.Interop.csproj │ ├── Sample.MultipleCameraCapture/ │ │ ├── Program.cs │ │ └── Sample.MultipleCameraCapture.csproj │ ├── Sample.UI/ │ │ ├── Program.cs │ │ └── Sample.UI.csproj │ └── Sample.VideoStreaming/ │ ├── Program.cs │ └── Sample.VideoStreaming.csproj └── Source/ ├── BitmapInterop/ │ ├── .nuSpec/ │ │ └── readmeImage.Bitmap.txt │ ├── BmpExtensions/ │ │ ├── BitmapConversion.cs │ │ ├── BmpIO.cs │ │ └── ColorConversion.cs │ └── Image.BitmapInterop.csproj ├── IO/ │ ├── .nuSpec/ │ │ └── readmeIO.txt │ ├── Base/ │ │ ├── Abstract/ │ │ │ ├── ImageStream.cs │ │ │ ├── ImageStreamReader.cs │ │ │ └── ImageStreamWriter.cs │ │ └── CvInvoke.cs │ ├── IO.csproj │ ├── ImageIO.cs │ ├── Readers/ │ │ ├── CameraCapture.cs │ │ ├── FileCapture.cs │ │ ├── ImageDirectoryCapture.cs │ │ └── VideoCaptureBase.cs │ ├── Utilities/ │ │ ├── NaturalSortComparer.cs │ │ └── PathExtensions.cs │ ├── Writers/ │ │ ├── ImageWriterExtension.cs │ │ └── VideoWriter.cs │ └── runtimes/ │ └── ubuntu.16.04-x64/ │ ├── libopencv_core.so.2.4 │ ├── libopencv_highgui.so.2.4 │ └── libopencv_video.so.2.4 ├── IO.Web/ │ ├── .nuSpec/ │ │ └── readmeIO.Web.txt │ ├── IO.Web.csproj │ ├── NamedPipeExtensions.cs │ └── WebImageExtensions.cs ├── Image/ │ ├── .nuSpec/ │ │ └── readmeImage.txt │ ├── ColorTypeConversions/ │ │ ├── ColorInfo.cs │ │ ├── ColorSpaces/ │ │ │ ├── Bgr.cs │ │ │ ├── Bgra.cs │ │ │ ├── Gray.cs │ │ │ ├── Hsv.cs │ │ │ ├── IColor.cs │ │ │ └── Rgb.cs │ │ └── Converters/ │ │ └── ColorConversionExtensions.cs │ ├── Extensions/ │ │ ├── BasicExtensions.cs │ │ ├── ChannelMerger.cs │ │ ├── ChannelSplitter.cs │ │ ├── Convert.cs │ │ ├── Copy.cs │ │ ├── ImageFlipping.cs │ │ └── SpatialConvolution.cs │ ├── Image.csproj │ ├── Interop/ │ │ ├── CvMat.cs │ │ └── IplImage.cs │ ├── Linq/ │ │ └── ImagingLinq.cs │ ├── ParallelLauncher.cs │ ├── Slice2D.cs │ └── Unmanaged/ │ ├── IImage.cs │ └── Image'1.cs ├── Primitives2D/ │ ├── Box2D/ │ │ └── Box2D.cs │ ├── Circle/ │ │ ├── Circle.cs │ │ └── CircleF.cs │ ├── Ellipse/ │ │ └── Ellipse.cs │ ├── Point/ │ │ ├── Point'1.cs │ │ └── PointExtensions.cs │ ├── Primitives2D.csproj │ ├── Rectangle/ │ │ └── RectangleExtensions.cs │ └── Size/ │ └── SizeExtensions.cs └── UI.Image/ ├── .nuSpec/ │ └── readmeUI.Image.txt ├── Base/ │ ├── CvCoreInvoke.cs │ └── CvInvoke.cs ├── Drawing.cs ├── ImageUI.cs ├── UI.Image.csproj └── runtimes/ └── ubuntu.16.04-x64/ ├── libopencv_core.so.2.4 └── libopencv_highgui.so.2.4 ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.sln.docstates # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ build/ bld/ [Bb]in/ [Oo]bj/ # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets !packages/*/build/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* #NUNIT *.VisualState.xml TestResult.xml *_i.c *_p.c *_i.h *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opensdf *.sdf *.cachefile # Visual Studio profiler *.psess *.vsp *.vspx # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding addin-in .JustCode # TeamCity is a build add-in # NuGet *.nuget.props *.nuget.targets **/packages/* !**/packages/build/ # User-specific files *.suo *.user *.userosscache *.sln.docstates # Build results [Dd]ebug/ [Rr]elease/ x64/ x86/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ # Visual Studio 2015 cache/options directory .vs/ # Visual Studio profiler *.psess *.vsp *.vspx *.sap # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ /Deploy/Nuget/NuGet.exe ================================================ FILE: Deploy/Licence.txt ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: Deploy/Nuget/Push.ps1 ================================================ #--references: # list files: https://medium.com/@victorleungtw/replace-text-in-xml-files-with-powershell-504d3e37a058 timeout /T 5 Write-Host Write-Host Pushing packages: $files = @(Get-ChildItem *.nupkg -Recurse) foreach($f in $files) { Write-Host $f $cmd = './nuget push "$f" -source https://www.nuget.org/api/v2/package' iex $cmd } Write-Host #pause ================================================ FILE: Directory.Build.props ================================================  netcoreapp2.2 preview bin\ false ================================================ FILE: DotImaging.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29102.190 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{80058A54-6223-480C-AA19-F99E7AE593F3}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{05BDC895-7F7B-4B6F-8D69-E7916837092D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Deploy", "Deploy", "{80FC5EA1-3478-4E7F-8B05-190DF6750EA4}" ProjectSection(SolutionItems) = preProject Deploy\Licence.txt = Deploy\Licence.txt EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Logo", "Logo", "{817B040E-5F27-4ACD-B1E4-F46452668A0E}" ProjectSection(SolutionItems) = preProject Deploy\Logo\DotImaging.pptx = Deploy\Logo\DotImaging.pptx Deploy\Logo\logo-big.png = Deploy\Logo\logo-big.png Deploy\Logo\logo-small.png = Deploy\Logo\logo-small.png EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Image.BitmapInterop", "Source\BitmapInterop\Image.BitmapInterop.csproj", "{CE222A84-B03B-4053-8BA4-F237063382F2}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Image", "Source\Image\Image.csproj", "{3CF8F155-3DA1-4529-9B28-D409E86ED4E2}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IO", "Source\IO\IO.csproj", "{ED70A44E-9443-4A28-9B95-31299F8B2D08}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IO.Web", "Source\IO.Web\IO.Web.csproj", "{B8404D66-B64E-43E0-9653-35FC6782072F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.VideoStreaming", "Samples\Sample.VideoStreaming\Sample.VideoStreaming.csproj", "{CB088D8A-3438-4DB9-87C2-99425FE27F07}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.Basic", "Samples\Sample.Basic\Sample.Basic.csproj", "{5F5FE08B-37C1-4C62-BB1A-DFFF61B3516A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.Interop", "Samples\Sample.Interop\Sample.Interop.csproj", "{E4ED626D-359B-493C-A72E-3738A5353D1B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.Capture", "Samples\Sample.Capture\Sample.Capture.csproj", "{D0C18418-5282-4BA8-ABF7-CC2A9A179517}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.CaptureAndRecord", "Samples\Sample.CaptureAndRecord\Sample.CaptureAndRecord.csproj", "{867ED0BD-FBFB-4C0C-A34B-D71361874AA0}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.ImageExtractor", "Samples\Sample.ImageExtractor\Sample.ImageExtractor.csproj", "{55FF1668-9501-4007-84D8-26EF860F0D0D}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.MultipleCameraCapture", "Samples\Sample.MultipleCameraCapture\Sample.MultipleCameraCapture.csproj", "{C30A145E-02FB-49B4-8F3E-6673AF9D121A}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuGet", "NuGet", "{44744CCA-2769-4607-AC90-78B6A11A2E77}" ProjectSection(SolutionItems) = preProject Deploy\Nuget\Push.ps1 = Deploy\Nuget\Push.ps1 Deploy\Nuget\UpdatePackageVersion.ps1 = Deploy\Nuget\UpdatePackageVersion.ps1 EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UI.Image", "Source\UI.Image\UI.Image.csproj", "{F021F056-59F7-4C49-9F0F-3BE6721F920F}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7C2B92C2-DD93-47F5-8ADA-BF21086EDCDD}" ProjectSection(SolutionItems) = preProject Directory.Build.props = Directory.Build.props README.md = README.md EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Primitives2D", "Source\Primitives2D\Primitives2D.csproj", "{CF955F14-669D-4802-A3A3-0CDA7601205E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {CE222A84-B03B-4053-8BA4-F237063382F2}.Debug|x64.ActiveCfg = Debug|Any CPU {CE222A84-B03B-4053-8BA4-F237063382F2}.Debug|x64.Build.0 = Debug|Any CPU {CE222A84-B03B-4053-8BA4-F237063382F2}.Release|x64.ActiveCfg = Release|Any CPU {CE222A84-B03B-4053-8BA4-F237063382F2}.Release|x64.Build.0 = Release|Any CPU {3CF8F155-3DA1-4529-9B28-D409E86ED4E2}.Debug|x64.ActiveCfg = Debug|Any CPU {3CF8F155-3DA1-4529-9B28-D409E86ED4E2}.Debug|x64.Build.0 = Debug|Any CPU {3CF8F155-3DA1-4529-9B28-D409E86ED4E2}.Release|x64.ActiveCfg = Release|Any CPU {3CF8F155-3DA1-4529-9B28-D409E86ED4E2}.Release|x64.Build.0 = Release|Any CPU {ED70A44E-9443-4A28-9B95-31299F8B2D08}.Debug|x64.ActiveCfg = Debug|x64 {ED70A44E-9443-4A28-9B95-31299F8B2D08}.Debug|x64.Build.0 = Debug|x64 {ED70A44E-9443-4A28-9B95-31299F8B2D08}.Release|x64.ActiveCfg = Release|x64 {ED70A44E-9443-4A28-9B95-31299F8B2D08}.Release|x64.Build.0 = Release|x64 {B8404D66-B64E-43E0-9653-35FC6782072F}.Debug|x64.ActiveCfg = Debug|Any CPU {B8404D66-B64E-43E0-9653-35FC6782072F}.Debug|x64.Build.0 = Debug|Any CPU {B8404D66-B64E-43E0-9653-35FC6782072F}.Release|x64.ActiveCfg = Release|Any CPU {B8404D66-B64E-43E0-9653-35FC6782072F}.Release|x64.Build.0 = Release|Any CPU {CB088D8A-3438-4DB9-87C2-99425FE27F07}.Debug|x64.ActiveCfg = Debug|x64 {CB088D8A-3438-4DB9-87C2-99425FE27F07}.Debug|x64.Build.0 = Debug|x64 {CB088D8A-3438-4DB9-87C2-99425FE27F07}.Release|x64.ActiveCfg = Release|x64 {CB088D8A-3438-4DB9-87C2-99425FE27F07}.Release|x64.Build.0 = Release|x64 {5F5FE08B-37C1-4C62-BB1A-DFFF61B3516A}.Debug|x64.ActiveCfg = Debug|x64 {5F5FE08B-37C1-4C62-BB1A-DFFF61B3516A}.Debug|x64.Build.0 = Debug|x64 {5F5FE08B-37C1-4C62-BB1A-DFFF61B3516A}.Release|x64.ActiveCfg = Release|x64 {5F5FE08B-37C1-4C62-BB1A-DFFF61B3516A}.Release|x64.Build.0 = Release|x64 {E4ED626D-359B-493C-A72E-3738A5353D1B}.Debug|x64.ActiveCfg = Debug|x64 {E4ED626D-359B-493C-A72E-3738A5353D1B}.Debug|x64.Build.0 = Debug|x64 {E4ED626D-359B-493C-A72E-3738A5353D1B}.Release|x64.ActiveCfg = Release|x64 {E4ED626D-359B-493C-A72E-3738A5353D1B}.Release|x64.Build.0 = Release|x64 {D0C18418-5282-4BA8-ABF7-CC2A9A179517}.Debug|x64.ActiveCfg = Debug|x64 {D0C18418-5282-4BA8-ABF7-CC2A9A179517}.Debug|x64.Build.0 = Debug|x64 {D0C18418-5282-4BA8-ABF7-CC2A9A179517}.Release|x64.ActiveCfg = Release|x64 {D0C18418-5282-4BA8-ABF7-CC2A9A179517}.Release|x64.Build.0 = Release|x64 {867ED0BD-FBFB-4C0C-A34B-D71361874AA0}.Debug|x64.ActiveCfg = Debug|x64 {867ED0BD-FBFB-4C0C-A34B-D71361874AA0}.Debug|x64.Build.0 = Debug|x64 {867ED0BD-FBFB-4C0C-A34B-D71361874AA0}.Release|x64.ActiveCfg = Release|x64 {867ED0BD-FBFB-4C0C-A34B-D71361874AA0}.Release|x64.Build.0 = Release|x64 {55FF1668-9501-4007-84D8-26EF860F0D0D}.Debug|x64.ActiveCfg = Debug|x64 {55FF1668-9501-4007-84D8-26EF860F0D0D}.Debug|x64.Build.0 = Debug|x64 {55FF1668-9501-4007-84D8-26EF860F0D0D}.Release|x64.ActiveCfg = Release|x64 {55FF1668-9501-4007-84D8-26EF860F0D0D}.Release|x64.Build.0 = Release|x64 {C30A145E-02FB-49B4-8F3E-6673AF9D121A}.Debug|x64.ActiveCfg = Debug|x64 {C30A145E-02FB-49B4-8F3E-6673AF9D121A}.Debug|x64.Build.0 = Debug|x64 {C30A145E-02FB-49B4-8F3E-6673AF9D121A}.Release|x64.ActiveCfg = Release|x64 {C30A145E-02FB-49B4-8F3E-6673AF9D121A}.Release|x64.Build.0 = Release|x64 {F021F056-59F7-4C49-9F0F-3BE6721F920F}.Debug|x64.ActiveCfg = Debug|x64 {F021F056-59F7-4C49-9F0F-3BE6721F920F}.Debug|x64.Build.0 = Debug|x64 {F021F056-59F7-4C49-9F0F-3BE6721F920F}.Release|x64.ActiveCfg = Release|x64 {F021F056-59F7-4C49-9F0F-3BE6721F920F}.Release|x64.Build.0 = Release|x64 {CF955F14-669D-4802-A3A3-0CDA7601205E}.Debug|x64.ActiveCfg = Debug|Any CPU {CF955F14-669D-4802-A3A3-0CDA7601205E}.Debug|x64.Build.0 = Debug|Any CPU {CF955F14-669D-4802-A3A3-0CDA7601205E}.Release|x64.ActiveCfg = Release|Any CPU {CF955F14-669D-4802-A3A3-0CDA7601205E}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {817B040E-5F27-4ACD-B1E4-F46452668A0E} = {80FC5EA1-3478-4E7F-8B05-190DF6750EA4} {CE222A84-B03B-4053-8BA4-F237063382F2} = {80058A54-6223-480C-AA19-F99E7AE593F3} {3CF8F155-3DA1-4529-9B28-D409E86ED4E2} = {80058A54-6223-480C-AA19-F99E7AE593F3} {ED70A44E-9443-4A28-9B95-31299F8B2D08} = {80058A54-6223-480C-AA19-F99E7AE593F3} {B8404D66-B64E-43E0-9653-35FC6782072F} = {80058A54-6223-480C-AA19-F99E7AE593F3} {CB088D8A-3438-4DB9-87C2-99425FE27F07} = {05BDC895-7F7B-4B6F-8D69-E7916837092D} {5F5FE08B-37C1-4C62-BB1A-DFFF61B3516A} = {05BDC895-7F7B-4B6F-8D69-E7916837092D} {E4ED626D-359B-493C-A72E-3738A5353D1B} = {05BDC895-7F7B-4B6F-8D69-E7916837092D} {D0C18418-5282-4BA8-ABF7-CC2A9A179517} = {05BDC895-7F7B-4B6F-8D69-E7916837092D} {867ED0BD-FBFB-4C0C-A34B-D71361874AA0} = {05BDC895-7F7B-4B6F-8D69-E7916837092D} {55FF1668-9501-4007-84D8-26EF860F0D0D} = {05BDC895-7F7B-4B6F-8D69-E7916837092D} {C30A145E-02FB-49B4-8F3E-6673AF9D121A} = {05BDC895-7F7B-4B6F-8D69-E7916837092D} {44744CCA-2769-4607-AC90-78B6A11A2E77} = {80FC5EA1-3478-4E7F-8B05-190DF6750EA4} {F021F056-59F7-4C49-9F0F-3BE6721F920F} = {80058A54-6223-480C-AA19-F99E7AE593F3} {CF955F14-669D-4802-A3A3-0CDA7601205E} = {80058A54-6223-480C-AA19-F99E7AE593F3} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DEAC2BC6-C697-4361-9909-CF7055FE9B05} EndGlobalSection EndGlobal ================================================ FILE: README.md ================================================

DotImaging logo

NuGet packages version

**DotImaging** - .NET array as imaging object The framework sets focus on .NET native array as primary imaging object, offers extensibility support via extensions, and provides unified platform-abstract imaging IO API. ## News + 5.2.0 version came out (19/02/2019) + Image enchacement library for DotImaging: DotDevignetting! ## So why DotImaging ? + Image as native .NET 2D array + portable* + lightweight + extensions, extensions, extensions.... *IO and Drawing assemlies depend on OpenCV ## Libraries / NuGet packages ###### Core + DotImaging.Image .NET image array extensions. Color and depth conversions. Slim unmanaged structure for fast pixel manipulation. > **Tutorial:** Portable Generic Image ``` csharp //convert to grayscale and flip Bgr[,] image = ImageIO.LoadColor("sample.jpg"); //IO package Gray[,] grayIm = image.ToGray() .Flip(FlipDirection.Horizontal); //get the modified blue channel var modifiedImage = image.AsEnumerable() .Select(x => x.B / 2) .ToArray2D(image.Size()); ``` + DotImaging.Primitives2D Portable 2D drawing primitives (Extensions for Point, Size, Rectangle and additional primitives) ###### IO + DotImaging.IO A unified API for IO image access (camera, file, image directory). Portable image loading/saving. > **Tutorial:** Portable Imaging IO ``` csharp var reader = new FileCapture("sample.mp4"); reader.Open(); Bgr[,] frame = null; while(true) { reader.ReadTo(ref frame); if (frame == null) break; frame.Show(scaleForm: true); //UI package } reader.Close(); ``` + DotImaging.IO.Web Image or video download/streaming (direct video link or Youtube links). ``` csharp //------get an image from the Web new Uri("http://vignette3.wikia.nocookie.net/disney/images/5/5d/Lena_headey_.jpg") .GetBytes().DecodeAsColorImage().Show(); //(Show - UI package) //------stream a video from Youtube var pipeName = new Uri("https://www.youtube.com/watch?v=Vpg9yizPP_g").NamedPipeFromYoutubeUri(); //Youtube var reader = new FileCapture(String.Format(@"\\.\pipe\{0}", pipeName)) //IO package //... (regular stream reading - see IO package sample) ``` ###### Interoperability + DotImaging.BitmapInterop Interoperability extensions between .NET array and System.Drawing.Bitmap. ``` csharp var image = new Gray[240, 320]; var bmp = image.ToBitmap(); //to Bitmap var imageFromBmp = bmp.ToArray() as Bgr[,]; //from Bitmap ``` ###### Extensions + DotImaging.UI Image preview dialog and drawing. ``` csharp Bgr[,] image = new Bgr[480, 640]; image.Show(); //show image (non-blocking) image.ShowDialog(); //show image (blocking) //draw something image.Draw(new Rectangle(50, 50, 200, 100), Bgr.Red, -1); image.Draw(new Circle(50, 50, 25), Bgr.Blue, 5); ``` ## Getting started + Just pick what you need. An appropriate readme file will be shown upon selected NuGet package installation. + Samples ## Final word If you like the project please **star it** in order to help to spread the word. That way you will make the framework more significant and in the same time you will motivate me to improve it, so the benefit is mutual. ================================================ FILE: Samples/Sample.Basic/Program.cs ================================================ using DotImaging; using System.Drawing; using System; using System.IO; namespace BasicImageOperations { static class Program { static void Main() { Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + ";runtimes/win10-x64/"); //only needed if projects are directly referenced //load from the Web var image = new Uri("http://vignette3.wikia.nocookie.net/disney/images/5/5d/Lena_headey_.jpg") .GetBytes() .DecodeAsColorImage(); //show image image.Show("New Lena"); //draw something image.DrawRectangle(new Rectangle(50, 50, 200, 100), Bgr.Red, -1); image.DrawText("Hello world!", DotImaging.Font.Big, new Point(10, 100), Bgr.White); //save and load image.Save("out.png"); ImageIO.LoadColor("out.png").ShowDialog("Saved image", autoSize: true); } } } ================================================ FILE: Samples/Sample.Basic/Sample.Basic.csproj ================================================  netcoreapp2.2 Exe x64 ================================================ FILE: Samples/Sample.Capture/Program.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using DotImaging; using System; using System.IO; namespace Capture { class Program { [STAThread] static void Main() { Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + ";runtimes/win10-x64/"); //only needed if projects are directly referenced Console.WriteLine("Press ESC to stop playing"); //var reader = new CameraCapture(0); //capture from camera //(reader as CameraCapture).FrameSize = new Size(640, 480); var reader = new FileCapture(Path.Combine(getResourceDir(), "Welcome.mp4")); //capture from video //var reader = new ImageDirectoryCapture(Path.Combine(getResourceDir(), "Sequence"), "*.jpg"); reader.Open(); Bgr[,] frame = null; do { reader.ReadTo(ref frame); if (frame == null) break; frame.Show(autoSize: true); } while (!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape)); reader.Dispose(); ImageUI.CloseAll(); } private static string getResourceDir() { return Path.Combine(new DirectoryInfo(Environment.CurrentDirectory).FullName, "Resources"); } } } ================================================ FILE: Samples/Sample.Capture/Sample.Capture.csproj ================================================  netcoreapp2.2 x64 DotImaging bin\ Exe Always ================================================ FILE: Samples/Sample.CaptureAndRecord/Program.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2016 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using DotImaging; using System; using System.IO; namespace CaptureAndRecording { static class Program { static void Main() { Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + ";runtimes/win10-x64/"); //only needed if projects are directly referenced //var reader = new CameraCapture(0); //capture from camera var reader = new FileCapture(Path.Combine(getResourceDir(), "Welcome.mp4")); reader.Open(); var writer = new VideoWriter(@"output.avi", reader.FrameSize, /*reader.FrameRate does not work Cameras*/ 30); //TODO: bug: FPS does not work for cameras writer.Open(); Bgr[,] frame = null; do { reader.ReadTo(ref frame); if (frame == null) break; using (var uFrame = frame.Lock()) { writer.Write(uFrame); } frame.Show(autoSize: true); } while (!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape)); reader.Dispose(); writer.Dispose(); ImageUI.CloseAll(); } private static string getResourceDir() { return Path.Combine(new DirectoryInfo(Environment.CurrentDirectory).FullName, "Resources"); } } } ================================================ FILE: Samples/Sample.CaptureAndRecord/Sample.CaptureAndRecord.csproj ================================================  netcoreapp2.2 x64 DotImaging bin\ Exe Always ================================================ FILE: Samples/Sample.ImageExtractor/Program.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2016 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using DotImaging; using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace ImageExtractor { class Program { static void Main(string[] args) { Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + ";runtimes/win10-x64/"); //only needed if projects are directly referenced //emulate input args string fileMask = Path.Combine(getResourceDir(), "Welcome.mp4"); if (args.Length == 1) fileMask = args[0]; var fileNames = enumerateFiles(fileMask); foreach (var fileName in fileNames) { extractVideo(fileName); } } private static void extractVideo(string fileName) { //get output dir (same as file name and in the same folder as video) var fileInfo = new FileInfo(fileName); var fileNameNoExt = fileInfo.Name.Replace(fileInfo.Extension, String.Empty); string outputDir = Path.Combine(fileInfo.DirectoryName, fileNameNoExt); //open video var reader = new FileCapture(fileName); reader.Open(); reader.SaveFrames(outputDir, "{0}.jpg", p => Console.Write($"\rExtracting: {(int)(p * 100)} %")); ImageUI.CloseAll(); } private static IEnumerable enumerateFiles(string fileMask) { var pathDelimiter = Path.DirectorySeparatorChar; fileMask = normalizePathDelimiters(fileMask, pathDelimiter.ToString()); string fileMaskWithoutPath = fileMask.Split(pathDelimiter).Last(); string path = fileMask.Replace(fileMaskWithoutPath, String.Empty); var fileNames = Directory.EnumerateFiles(path, fileMaskWithoutPath); return fileNames; } private static string getResourceDir() { return Path.Combine(new DirectoryInfo(Environment.CurrentDirectory).FullName, "Resources"); } private static string normalizePathDelimiters(string path, string normalizedDelimiter) //TODO: replace with extension when available { return path.Replace("//", normalizedDelimiter) .Replace(@"\", normalizedDelimiter) .Replace(@"\\", normalizedDelimiter) .Replace(@"/", normalizedDelimiter); } } } ================================================ FILE: Samples/Sample.ImageExtractor/Sample.ImageExtractor.csproj ================================================  netcoreapp2.2 x64 DotImaging bin\ Exe Always ================================================ FILE: Samples/Sample.Interop/Program.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2016 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using DotImaging; using System; using System.IO; namespace GenericImageInteropDemo { class Program { static void Main(string[] args) { Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + ";runtimes/win10-x64/"); //only needed if projects are directly referenced var img = new Bgr[480, 640]; //*********************************************************************************************************************************************************************** Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("********* TColor[,] <=> Image<> conversions (built-in) ****************"); Console.ResetColor(); //to Image<> Image> lockedImg = img.Lock(); //from Image<> var arr = lockedImg.Clone(); //*********************************************************************************************************************************************************************** Console.WriteLine(); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("********* Image<,> <=> OpenCV conversions (built-in) ****************"); Console.ResetColor(); //to IplImage IplImage iplImage; using (var uImg = img.Lock()) { iplImage = uImg.AsCvIplImage(); //data is shared } //from IplImage var imgFromIpl = iplImage.AsImage(); //*********************************************************************************************************************************************************************** Console.WriteLine(); Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("*********** Image<,> <=> Bitmap conversions (BitmapInterop) ****************"); Console.ResetColor(); //to Bitmap var bmp = img.ToBitmap(); //from Bitmap var imgFromBmp = bmp.ToImage>(); } } } ================================================ FILE: Samples/Sample.Interop/Sample.Interop.csproj ================================================  netcoreapp2.2 x64 DotImaging bin\ Exe ================================================ FILE: Samples/Sample.MultipleCameraCapture/Program.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2016 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using DotImaging; using System.Collections.Generic; using System.IO; namespace MultipleCameraCapture { static class Program { static void Main() { Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + ";runtimes/win10-x64/"); //only needed if projects are directly referenced Console.WriteLine("Press ESC to stop playing"); List captures = new List(); var cameraCount = CameraCapture.CameraCount; if (cameraCount == 0) { Console.WriteLine("No camera device is present."); return; } //initialize for (int camIdx = 0; camIdx < cameraCount; camIdx++) { var cap = new CameraCapture(camIdx); cap.Open(); captures.Add(cap); } //grab frames Bgr[][,] frames = new Bgr[cameraCount][,]; do { for (int camIdx = 0; camIdx < cameraCount; camIdx++) { captures[camIdx].ReadTo(ref frames[camIdx]); if (frames[camIdx] == null) break; frames[camIdx].Show(String.Format("Camera {0}", camIdx), autoSize: true); } } while (!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape)); //dispose captures.ForEach(x => x.Dispose()); ImageUI.CloseAll(); } } } ================================================ FILE: Samples/Sample.MultipleCameraCapture/Sample.MultipleCameraCapture.csproj ================================================  netcoreapp2.2 x64 DotImaging bin\ Exe ================================================ FILE: Samples/Sample.UI/Program.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2016 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using DotImaging; using DotImaging.Linq; using System.Linq; using System; using System.Threading; using System.IO; namespace UIDemo { class Program { [STAThread] static void Main(string[] args) { Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + ";runtimes/win10-x64/"); //only needed if projects are directly referenced //select color Bgr[,] image = new Bgr[480, 640]; Hsv color = UI.PickColor(Bgr.Red).ToHsv(); //select mask Gray[,] mask = image.GetMask(); if (mask.AsEnumerable().Sum(x => x.Intensity) == 0) //if the mask is empty mask.SetValue>(Byte.MaxValue); //increase saturation incrementally for (int s = 0; s <= Byte.MaxValue; s++) { color.S = (byte)s; image.SetValue>(color.ToBgr(), mask); image.Show(scaleForm: true); ((double)s / Byte.MaxValue).Progress(message: "Changing saturation"); Thread.Sleep(50); } //save last image string fileName = UI.SaveImage(); if (fileName != null) image.Save(fileName); //close all UI.CloseAll(); } } } ================================================ FILE: Samples/Sample.UI/Sample.UI.csproj ================================================  net47 DotImaging bin\ Exe ================================================ FILE: Samples/Sample.VideoStreaming/Program.cs ================================================ using DotImaging; using System; using System.Diagnostics; using System.IO; namespace YoutubeStreaming { class Program { public static void Main() { Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); Environment.SetEnvironmentVariable("PATH", Environment.GetEnvironmentVariable("PATH") + ";runtimes/win10-x64/"); //only needed if projects are directly referenced var sourceName = String.Empty; //video over pipe (direct link and Youtube) (do not support seek) //var pipeName = new Uri("http://trailers.divx.com/divx_prod/divx_plus_hd_showcase/BigBuckBunny_DivX_HD720p_ASP.divx").NamedPipeFromVideoUri(); //web-video var pipeName = new Uri("https://www.youtube.com/watch?v=Vpg9yizPP_g").NamedPipeFromYoutubeUri(); //Youtube sourceName = String.Format(@"\\.\pipe\{0}", pipeName); //video http link (Supports seek) //sourceName = "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"; //--------------------------------------------- ImageStreamReader reader = new FileCapture(sourceName); reader.Open(); //seek if you can if(reader.CanSeek) reader.Seek((int)(reader.Length * 0.25), System.IO.SeekOrigin.Begin); //read video frames Bgr[,] frame = null; while(true) { reader.ReadTo(ref frame); if (frame == null) break; frame.Show(autoSize: false); Console.Write($"\r Received: {reader.Position * 100 / reader.Length}%"); } Console.WriteLine("The end."); //--------------------------------------------------------------------------- ImageUI.CloseAll(); Console.WriteLine("Downloading video..."); string fileExtension; var downloadPipeName = new Uri("https://www.youtube.com/watch?v=Vpg9yizPP_g").NamedPipeFromYoutubeUri(out fileExtension); //Youtube downloadPipeName.SaveNamedPipeStream("out" + fileExtension); Console.WriteLine("Video saved."); Process.Start("out" + fileExtension); //open local file } } } ================================================ FILE: Samples/Sample.VideoStreaming/Sample.VideoStreaming.csproj ================================================  netcoreapp2.2 x64 DotImaging bin\ Exe ================================================ FILE: Source/BitmapInterop/.nuSpec/readmeImage.Bitmap.txt ================================================ Provides extensions for interoperability with System.Drawing.Bitmap, Point, PointF, Color and drawing extensions. 1) Array <-> Bitmap conversion: var image = new Gray[240, 320]; var bmp = image.ToBitmap(); var imageFromBmp = bmp.ToArray() as Bgr[,]; 2) System.Drawing.Color <-> DotImaging color conversion: var aquaColor = System.Drawing.Color.Aqua.ToBgr(); 3) Save bitmap with quality selection var bmp = Bitmap.FromFile("sample.bmp"); bmp.Save("compressed.jpg", 85); Discover more extensions as you type :) ================================================ FILE: Source/BitmapInterop/BmpExtensions/BitmapConversion.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; namespace DotImaging { /// /// Provides conversion extension methods between generic image and . /// public static class BitmapConversionExtensions { #region Conversion from Bitmap static Dictionary mapingTable = new Dictionary { { typeof(Gray), PixelFormat.Format8bppIndexed }, { typeof(Gray), PixelFormat.Format16bppGrayScale }, { typeof(Bgr), PixelFormat.Format24bppRgb }, { typeof(Bgra), PixelFormat.Format32bppArgb }, { typeof(Bgr), PixelFormat.Format48bppRgb }, { typeof(Bgra), PixelFormat.Format64bppArgb }, }; /// /// Converts a bitmap to an image (copies data). /// /// Input bitmap. /// Target color type. /// 2D array. public static TColor[,] ToImage(this Bitmap bmp) where TColor: unmanaged, IColor { if (mapingTable.TryGetValue(typeof(TColor), out var targetPixelFmt) == false) throw new NotSupportedException("Target mapping not found."); TColor[,] arr = null; using (Bitmap targetBmp = bmp.Clone(new Rectangle(0, 0, bmp.Width, bmp.Height), targetPixelFmt)) { var bmpData = targetBmp.LockBits(ImageLockMode.ReadOnly); arr = new TColor[targetBmp.Height, targetBmp.Width]; using (var img = arr.Lock()) { Copy.UnsafeCopy2D(bmpData.Scan0, img.ImageData, bmpData.Stride, img.Stride, bmpData.Height); } targetBmp.UnlockBits(bmpData); } return arr; } #endregion #region Conversion To Bitmap private static Bitmap toBitmap(IImage img, PixelFormat pixelFormat) { var bmp = new Bitmap(img.Width, img.Height, pixelFormat); var bmpData = bmp.LockBits(ImageLockMode.WriteOnly); Copy.UnsafeCopy2D(img.ImageData, bmpData.Scan0, img.Stride, bmpData.Stride, bmpData.Height); bmp.UnlockBits(bmpData); if (pixelFormat == PixelFormat.Format8bppIndexed) bmp.SetGrayscalePalette(); return bmp; } /// /// Converts an image to an bitmap. /// /// Input image. /// Bitmap public static Bitmap ToBitmap(this Image> img) { return toBitmap(img, PixelFormat.Format8bppIndexed); } /// /// Converts an image to an bitmap. /// /// Input image. /// Bitmap public static Bitmap ToBitmap(this Image> img) { return toBitmap(img, PixelFormat.Format16bppGrayScale); } /// /// Converts an image to an bitmap. /// /// Input image. /// Bitmap public static Bitmap ToBitmap(this Image> img) { return toBitmap(img, PixelFormat.Format24bppRgb); } /// /// Converts an image to an bitmap. /// /// Input image. /// Bitmap public static Bitmap ToBitmap(this Image> img) { return toBitmap(img, PixelFormat.Format32bppArgb); } /// /// Converts an image to an bitmap. /// /// Input image. /// Bitmap public static Bitmap ToBitmap(this Image> img) { return toBitmap(img, PixelFormat.Format48bppRgb); } /// /// Converts an image to an bitmap. /// /// Input image. /// Bitmap public static Bitmap ToBitmap(this Image> img) { return toBitmap(img, PixelFormat.Format64bppArgb); } /// /// Converts an image to an bitmap. /// /// Input image. /// Bitmap public static Bitmap ToBitmap(this Gray[,] img) { Bitmap bmp = null; using (var uImg = img.Lock()) { bmp = toBitmap(uImg, PixelFormat.Format8bppIndexed); } return bmp; } /// /// Converts an image to an bitmap. /// /// Input image. /// Bitmap public static Bitmap ToBitmap(this Gray[,] img) { Bitmap bmp = null; using (var uImg = img.Lock()) { bmp = toBitmap(uImg, PixelFormat.Format16bppGrayScale); } return bmp; } /// /// Converts an image to an bitmap. /// /// Input image. /// Bitmap public static Bitmap ToBitmap(this Bgr[,] img) { Bitmap bmp = null; using (var uImg = img.Lock()) { bmp = toBitmap(uImg, PixelFormat.Format24bppRgb); } return bmp; } /// /// Converts an image to an bitmap. /// /// Input image. /// Bitmap public static Bitmap ToBitmap(this Bgra[,] img) { Bitmap bmp = null; using (var uImg = img.Lock()) { bmp = toBitmap(uImg, PixelFormat.Format32bppArgb); } return bmp; } /// /// Converts an image to an bitmap. /// /// Input image. /// Bitmap public static Bitmap ToBitmap(this Bgr[,] img) { Bitmap bmp = null; using (var uImg = img.Lock()) { bmp = toBitmap(uImg, PixelFormat.Format48bppRgb); } return bmp; } /// /// Converts an image to an bitmap. /// /// Input image. /// Bitmap public static Bitmap ToBitmap(this Bgra[,] img) { Bitmap bmp = null; using (var uImg = img.Lock()) { bmp = toBitmap(uImg, PixelFormat.Format64bppArgb); } return bmp; } #endregion #region Cast to Bitmap private static Bitmap asBitmap(IImage img, PixelFormat pixelFormat) { var bmp = new Bitmap(img.Width, img.Height, img.Stride, pixelFormat, img.ImageData); if (pixelFormat == PixelFormat.Format8bppIndexed) bmp.SetGrayscalePalette(); return bmp; } /// /// Casts an image to an bitmap. /// Notice that GDI+ does not support bitmaps which stride is not 4. /// /// Input image. /// Bitmap public static Bitmap AsBitmap(this Image> img) { return asBitmap(img, PixelFormat.Format8bppIndexed); } /// /// Casts an image to an bitmap. /// Notice that GDI+ does not support bitmaps which stride is not 4. /// /// Input image. /// Bitmap public static Bitmap AsBitmap(this Image> img) { return asBitmap(img, PixelFormat.Format16bppGrayScale); } /// /// Casts an image to an bitmap. /// Notice that GDI+ does not support bitmaps which stride is not 4. /// /// Input image. /// Bitmap public static Bitmap AsBitmap(this Image> img) { return asBitmap(img, PixelFormat.Format24bppRgb); } /// /// Casts an image to an bitmap. /// Notice that GDI+ does not support bitmaps which stride is not 4. /// /// Input image. /// Bitmap public static Bitmap AsBitmap(this Image> img) { return asBitmap(img, PixelFormat.Format32bppArgb); } /// /// Casts an image to an bitmap. /// Notice that GDI+ does not support bitmaps which stride is not 4. /// /// Input image. /// Bitmap public static Bitmap AsBitmap(this Image> img) { return asBitmap(img, PixelFormat.Format48bppRgb); } /// /// Casts an image to an bitmap. /// Notice that GDI+ does not support bitmaps which stride is not 4. /// /// Input image. /// Bitmap public static Bitmap AsBitmap(this Image> img) { return asBitmap(img, PixelFormat.Format64bppArgb); } #endregion #region Misc /// /// Replaces color palette entries with grayscale intensities (256 entries). /// /// The 8-bpp grayscale image. public static void SetGrayscalePalette(this Bitmap image) { if (image.PixelFormat != PixelFormat.Format8bppIndexed) throw new ArgumentException("The provided image must have 8bpp pixel format."); var palette = image.Palette; for (int i = 0; i < (Byte.MaxValue + 1); i++) { palette.Entries[i] = Color.FromArgb(i, i, i); } image.Palette = palette; } /// /// Lock a into system memory. /// /// Bitmap to lock. /// Specifies the access level. /// Bitmap data. public static BitmapData LockBits(this Bitmap bmp, ImageLockMode imageLockMode = ImageLockMode.ReadWrite) { return bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), imageLockMode, bmp.PixelFormat); } #endregion } } ================================================ FILE: Source/BitmapInterop/BmpExtensions/BmpIO.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Collections.Generic; using System.Drawing.Imaging; using System.IO; namespace DotImaging { /// /// Bitmap file save extensions. /// public static class BmpIO { static Dictionary codecs = null; static BmpIO() { codecs = new Dictionary(); codecs.Add(".jpg", getEncoder(ImageFormat.Jpeg)); codecs.Add(".jpeg", getEncoder(ImageFormat.Jpeg)); codecs.Add(".png", getEncoder(ImageFormat.Png)); } private static ImageCodecInfo getEncoder(ImageFormat format) { ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); foreach (ImageCodecInfo codec in codecs) { if (codec.FormatID == format.Guid) { return codec; } } return null; } /// /// Saves the specified image. /// /// Quality parameter is only supported for JPEG, PNG file types. /// For other file types this value is omitted. /// /// /// Image. /// Target stream. /// Image format. /// Quality parameter [0..100] where 0 means maximum compression. public static void Save(this System.Drawing.Image image, Stream targetStream, ImageFormat imageFormat, int quality = 90) { var encoder = getEncoder(imageFormat); if (encoder != null) { System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality; EncoderParameters myEncoderParameters = new EncoderParameters(1); myEncoderParameters.Param[0] = new EncoderParameter(myEncoder, quality); image.Save(targetStream, encoder, myEncoderParameters); } else { image.Save(targetStream, imageFormat); } } /// /// Saves the specified image. /// /// Quality parameter is only supported for JPEG, PNG file types. /// For other file types this value is omitted. /// /// /// Image. /// File name. /// Quality parameter [0..100] where 0 means maximum compression. public static void Save(this System.Drawing.Image image, string filename, int quality = 90) { codecs.TryGetValue(new FileInfo(filename).Extension, out ImageCodecInfo codec); if (codec == null) { image.Save(filename); return; } System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality; EncoderParameters myEncoderParameters = new EncoderParameters(1); myEncoderParameters.Param[0] = new EncoderParameter(myEncoder, quality); image.Save(filename, codec, myEncoderParameters); } } } ================================================ FILE: Source/BitmapInterop/BmpExtensions/ColorConversion.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Drawing; namespace DotImaging { /// /// Contains color format conversion extensions. /// public static class ColorConversion { /// /// Gets System.Drawing.Color from Bgr8 color. /// /// Color. /// Opacity. If color has 4 channels opacity is discarded. /// System.Drawing.Color public static System.Drawing.Color ToColor(this Gray color, byte opacity = Byte.MaxValue) { return Color.FromArgb(opacity, color.Intensity, color.Intensity, color.Intensity); } /// /// Gets System.Drawing.Color from Bgr8 color. /// /// Color. /// Opacity. If color has 4 channels opacity is discarded. /// System.Drawing.Color public static System.Drawing.Color ToColor(this Bgr color, byte opacity = Byte.MaxValue) { return Color.FromArgb(opacity, color.R, color.G, color.B); } /// /// Gets System.Drawing.Color from Bgra8 color. /// /// Color. /// System.Drawing.Color public static System.Drawing.Color ToColor(this Bgra color) { return Color.FromArgb(color.A, color.R, color.G, color.B); } /// /// Converts (casts) the color into 32-bit BGR color. /// /// Color. /// Bgr representation. public static Bgr ToBgr(this System.Drawing.Color color) { return new Bgr { B = color.B, G = color.G, R = color.R }; } } } ================================================ FILE: Source/BitmapInterop/Image.BitmapInterop.csproj ================================================  DotImaging.BitmapInterop DotImaging AnyCPU bin\DotImaging.BitmapInterop.xml true 5.3.0 DotImaging.BitmapInterop Extensions for interoperability with System.Drawing.Bitmap. imaging interoperability extensions, GDI Darko Jurić Darko Jurić https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Licence.txt https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Logo/logo-small.png https://raw.githubusercontent.com/dajuric/dot-imaging/ https://raw.githubusercontent.com/dajuric/dot-imaging/ true ../../Deploy/NuGet/bin/ Readme.txt ================================================ FILE: Source/IO/.nuSpec/readmeIO.txt ================================================ Unified stream-like platform-abstract API for IO video access: web-camera support, various video-format reading / writing, image-directory reader. Image loading/saving (file or in-memory). 1) image loading / saving: Bgr[,] image = ImageIO.LoadColor("sample.jpg"); //load Bgr color image Gray[,] hdrImage = (ImageIO.LoadUnchanged("hdrImage.png") as Image>).Clone(); //load HDR grayscale (or any other) image image.Save("image.png"); 2) image in-memory encoding / decoding Bgr[,] bgrIm = ImageIO.LoadColor("sample.jpg"); byte[] encodedBgr = bgrIm.EncodeAsJpeg(); //or png, bmp Bgr[,] decodedBgr = encodedBgr.DecodeAsColorImage(); 3) media (camera, video, image-directory) capture: ImageStreamReader reader = new CameraCapture(); //use specific class for device-specific properties (e.g. exposure, image name, ...) reader.Open(); //read single frame var frame = reader.Read().ToBgr(); reader.Close(); 4) video writer: ImageStreamWriter videoWriter = new VideoWriter("out.avi", new Size(1280, 1024)); var image = new Bgr[1024, 1280]; videoWriter.Write(image.Lock()); //write a single frame videoWriter.Close(); 5) frame extraction: var reader = new FileCapture(fileName); reader.Open(); reader.SaveFrames(outputDir, "{0}.jpg", (percentage) => { ((double)percentage).Progress(message: "Extracting video..."); }); reader.Close(); Discover more types as you type :) ================================================ FILE: Source/IO/Base/Abstract/ImageStream.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.IO; namespace DotImaging { /// /// Provides the base class for the image stream. /// /// Image type. public abstract class ImageStream: IDisposable { /// /// Initializes a new instance of . /// protected ImageStream() { this.CanSeek = false; this.IsLiveStream = false; } /// /// When overridden in a derived class, gets the length in number of frames. /// public abstract long Length { get; } /// /// When overridden in a derived class, gets the next frame index. /// public virtual long Position { get; protected set; } /// /// Gets whether the stream is live stream meaning that its length is not constant. /// Those streams are usually not seek-able. See also: . /// public virtual bool IsLiveStream { get; protected set; } /// /// Gets a value indicating whether the current stream supports seeking. /// public virtual bool CanSeek { get; protected set; } /// /// When overridden in a derived class, sets the position within the current stream. /// /// A frame index offset relative to the origin parameter. /// A value of type System.IO.SeekOrigin indicating the reference point used to obtain the new position. /// The new position within the current stream. /// Seek operation is not supported by the current stream. public virtual long Seek(long offset, System.IO.SeekOrigin origin = SeekOrigin.Current) { if (!this.CanSeek) throw new NotSupportedException("Seek operation is not supported by the current stream."); long newPosition = 0; switch (origin) { case SeekOrigin.Begin: newPosition = offset; break; case SeekOrigin.Current: newPosition = this.Position + offset; break; case SeekOrigin.End: newPosition = this.Length + offset; break; } var currentFrame = System.Math.Min(this.Length - 1, System.Math.Max(0, newPosition)); return currentFrame; } /// /// Closes the stream and releases all resources. /// Use Dispose function rather than Close function. /// public virtual void Dispose() { this.Close(); } /// /// When overridden in a derived class, opens the current stream. /// public abstract void Open(); /// /// When overridden in a derived class, closes the current stream and releases any resources associated with the current stream. /// This function is internally called by . /// public abstract void Close(); } } ================================================ FILE: Source/IO/Base/Abstract/ImageStreamReader.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Collections; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using System; namespace DotImaging { /// /// Image stream reader abstract class. /// See generic class also. /// public abstract class ImageStreamReader: ImageStreamReader { } /// /// Image stream writer abstract class. /// It is the base class for classes providing image stream reading. /// /// Image type. public abstract class ImageStreamReader : ImageStream, IEnumerable { /// /// Initializes a new instance of the image reader class. /// protected ImageStreamReader() { this.ReadTimeout = 100; } /// /// Gets or sets a value, in milliseconds, that determines how long the stream will attempt to read before timing out. /// public int ReadTimeout { get; set; } /// /// Creates and starts the task responsible for frame reading. /// If this function is called must be handled by a user itself. /// /// By using this function reading from some streams can be accelerated. /// /// /// A image reading task. public Task ReadAsync() { var readTask = new Task(() => { TImage result; ReadInternal(out result); return result; }); readTask.Start(); return readTask; } /// /// Reads an image from the current stream /// and advances the position within the stream by 1 element. /// /// If a null is returned this can be due to has been reached. /// Read image. public TImage Read(out bool isExpired) { var readTask = ReadAsync(); readTask.Wait(this.ReadTimeout); isExpired = !readTask.IsCompleted; return readTask.Result; } /// /// Reads an image from the current stream /// and advances the position within the stream by usually 1 element. /// /// Read image. public TImage Read() { bool isExpired; return Read(out isExpired); } /// /// When overridden in a derived class returns an image and a status. /// Position is advanced. /// /// Read image. /// protected abstract bool ReadInternal(out TImage image); #region IEnumerable /// /// Gets the enumerator for the stream. /// If the stream does not support seek, an exception will be thrown during iteration. /// /// Enumerator for the stream. public IEnumerator GetEnumerator() { return new ImageStreamReaderEnumerator(this); } /// /// Gets the enumerator for the stream. /// If the stream does not support seek, an exception will be thrown during iteration. /// /// Enumerator for the stream. System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } #endregion } /// /// Enumerator for the image stream. /// Stream must support seek operation. /// /// Image type. public class ImageStreamReaderEnumerator : IEnumerator { ImageStreamReader streamableSource; long length = -1; int position; /// /// Creates new image stream iterator. /// /// Image stream. public ImageStreamReaderEnumerator(ImageStreamReader streamableSource) { this.streamableSource = streamableSource; this.length = streamableSource.Length; Reset(); } /// /// Moves the position of the iterator by 1. /// /// True if the position increment is valid, false otherwise. public bool MoveNext() { position++; return position < length; } /// /// Resets the enumerator, /// public void Reset() { streamableSource.Seek(0, SeekOrigin.Begin); position = -1; } /// /// Gets the current image within the stream. /// public TImage Current { get { var realPos = streamableSource.Position; if (position != realPos) streamableSource.Seek(position, SeekOrigin.Begin); var currentImage = streamableSource.Read(); return currentImage; } } /// /// Gets the current image within the stream. /// object System.Collections.IEnumerator.Current { get { return this.Current; } } bool isDisposed = false; /// /// Disposes the iterator and resets the position within the stream. /// public void Dispose() { if (!isDisposed) { Reset(); isDisposed = true; } } } /// /// Provides extensions for image stream. /// public static class ImageStreamReaderExtensions { /// /// Calls read function defined by the stream and converts an returned image if necessary. /// If the image can not be read (null), null is returned. /// /// Image stream. /// Converted image or null if the image can not be read. public static Image ReadAs(this ImageStreamReader imageStream) where TColor: unmanaged { var image = imageStream.Read(); if (image == null) return null; return image as Image; } /// /// Reads an element form the input stream and fills the specified buffer. /// If the read element does not match the specified type a null value will be written. /// /// Color type. /// Image source stream. /// /// Buffer to write to. /// The specified buffer can be null, as it is managed by the function itself. /// public static void ReadTo(this ImageStreamReader imageStream, ref TColor[,] buffer) where TColor: unmanaged { imageStream.ReadAs().CopyToOrCreate(ref buffer); } } } ================================================ FILE: Source/IO/Base/Abstract/ImageStreamWriter.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Threading.Tasks; using System; namespace DotImaging { /// /// Image stream writer abstract class. /// See generic class also. /// public abstract class ImageStreamWriter : ImageStreamWriter { } /// /// Image stream writer abstract class. /// It is the base class for classes providing image stream reading. /// /// Image type. public abstract class ImageStreamWriter : ImageStream { /// /// Initializes a new instance of the image stream writer class. /// protected ImageStreamWriter() { this.WriteTimeout = 500; } /// /// Gets or sets a value, in milliseconds, that determines how long the writer will attempt to write before timing out. /// public int WriteTimeout { get; set; } /// /// Creates and starts the task responsible for frame writing. /// If this function is called must be handled by a user itself. /// /// By using this function writing to some streams can be accelerated. /// /// /// An image writing task. public Task WriteAsync(TImage image) { var writeTask = new Task(() => { bool success = WriteInternal(image); return success; }); writeTask.Start(); return writeTask; } /// /// Writes an image from the current stream /// and advances the position within the stream by 1 element. /// /// /// True if the operation is successfully completed, /// false if the writer failed to write or the has been reached. /// public bool Write(TImage image) { var writeTask = WriteAsync(image); writeTask.Wait(this.WriteTimeout); return writeTask.IsCompleted && writeTask.Result; } /// /// When overridden in a derived class returns an image and a status. /// Position is advanced. /// /// Image to write. /// True if successful, false otherwise. protected abstract bool WriteInternal(TImage image); } /// /// Provides extensions for an image stream writer. /// public static class ImageStreamWriterExtensions { /// /// Writes a single image into the specified stream. /// /// Color type. /// image stream writer. /// Image to write. /// True if the writing operation is successful, false otherwise. public static bool Write(this ImageStreamWriter> writer, TColor[,] image) where TColor: unmanaged, IColor { bool result = false; using (var uImg = image.Lock()) { result = writer.Write(uImg); } return result; } } } ================================================ FILE: Source/IO/Base/CvInvoke.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Drawing; using System; using System.Runtime.InteropServices; using System.Security; namespace DotImaging { /// /// OpenCV video codec name. /// public class VideoCodec { /// /// MPEG1 codec name: "PIM1". /// public static readonly VideoCodec MPEG1 = VideoCodec.FromName('P', 'I', 'M', '1'); /// /// Motion JPEG codec name: "MJPG". /// public static readonly VideoCodec MotionJpeg = VideoCodec.FromName('M', 'J', 'P', 'G'); /// /// Intel YUV codec name: "IYUV". /// public static readonly VideoCodec IntelYUV = VideoCodec.FromName('I', 'Y', 'U', 'V'); /// /// User selection - on Windows dialog will be opened. Value: -1. /// public static readonly VideoCodec UserSelection = new VideoCodec(-1); private const int CODEC_NAME_LENGTH = 4; int codec; /// /// Creates new video codec from an id. /// /// Codec id. private VideoCodec(int codec) { this.codec = codec; } /// /// Creates new video codec id from 4-character code. For example, FromName('P','I','M','1') is MPEG-1 codec, FromName('M','J','P','G') is motion-jpeg codec etc. /// /// First char. /// Second char. /// Third char. /// Fourth char. /// Video codec. public static VideoCodec FromName(char c1, char c2, char c3, char c4) { int codec = (c1 & 255) + ((c2 & 255) << 8) + ((c3 & 255) << 16) + ((c4 & 255) << 24); return new VideoCodec(codec); } /// /// Creates new video codec id from 4-character string. /// /// 4-character string codec name. /// Video codec. public static VideoCodec FromName(string codecName) { if (codecName.Length != CODEC_NAME_LENGTH) throw new Exception("Codec name is 4-characters long!"); return VideoCodec.FromName(codecName[0], codecName[1], codecName[2], codecName[3]); } /// /// Casts video codec to an 32-bit integer. /// /// Video codec. /// 32-bit integer representation of the video codec. public static implicit operator int(VideoCodec videoCodec) { return videoCodec.codec; } /// /// Creates video codec from the 32-bit integer. /// /// 32-bit code. /// New codec name. public static explicit operator VideoCodec(int code) { return new VideoCodec(code); } /// /// Creates video codec from the 4-character string. /// /// 4-character string. /// New codec name. /// Invalid string length. public static explicit operator VideoCodec(string code) { return VideoCodec.FromName(code); } /// /// Gets the string representation of the codec name. /// /// String representation. public override string ToString() { unsafe { fixed (int* intPtr = &this.codec) { sbyte* chPtr = (sbyte*)intPtr; return new string(chPtr, 0, CODEC_NAME_LENGTH); } } } } /// /// OpenCV capture properties for camera and video. /// internal enum CaptureProperty: int { PosMsec = 0, PosFrames = 1, FrameWidth = 3, FrameHeight = 4, FPS = 5, FrameCount = 7, /************** camera properties ******************/ Brightness = 10, Contrast = 11, Saturation = 12, Hue = 13, Gain = 14, Exposure = 15, /************** camera properties ******************/ ConvertRGB = 16 } /// /// OpenCV image load mode. /// [Flags] internal enum ImageLoadType : int { /// /// Loads the image as is (including the alpha channel if present) /// Unchanged = -1, /// /// Loads the image as an intensity image /// Grayscale = 0, /// /// Loads the image in the RGB format /// Color = 1, /// /// Loads the image of any color /// AnyColor = 4, /// /// Loads the image of any depth /// AnyDepth = 2 } /// /// Internal class for OpenCV core / highgui library invocation. /// internal static class CvInvoke { public const CallingConvention CvCallingConvention = CallingConvention.Cdecl; public const string OPENCV_CORE_LIBRARY = "opencv_core2412"; public const string OPENCV_HIGHGUI_LIBRARY = "opencv_highgui2412"; #region Core [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern void cvReleaseMat(ref CvMat* mat); //[SuppressUnmanagedCodeSecurity] [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern void cvReleaseImage(ref IplImage* image); #endregion #region Video reader //[SuppressUnmanagedCodeSecurity] [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public static extern IntPtr cvCreateCameraCapture(int index); [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public static extern IntPtr cvCreateFileCapture([MarshalAs(UnmanagedType.LPStr)] string filename); //[SuppressUnmanagedCodeSecurity] [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public static extern void cvReleaseCapture(ref IntPtr capture); //[SuppressUnmanagedCodeSecurity] [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public static extern int cvGrabFrame(IntPtr capture); //[SuppressUnmanagedCodeSecurity] [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public static extern IntPtr cvQueryFrame(IntPtr capture); //[SuppressUnmanagedCodeSecurity] [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public static extern double cvGetCaptureProperty(IntPtr capture, CaptureProperty propertyId); //[SuppressUnmanagedCodeSecurity] [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool cvSetCaptureProperty(IntPtr capture, CaptureProperty propertyId, double value); public static Size GetImageSize(IntPtr capturePtr) { return new Size { Width = (int)CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.FrameWidth), Height = (int)CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.FrameHeight) }; } public static bool SetImageSize(IntPtr capturePtr, Size newSize) { bool success; success = CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.FrameWidth, newSize.Width); success &= CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.FrameHeight, newSize.Height); return success; } #endregion #region Video writer /// /// Creates video writer structure. /// /// Name of the output video file. /// 4-character code of codec used to compress the frames. See class. /// Frame rate of the created video stream. /// Size of video frames. /// If true, the encoder will expect and encode color frames, otherwise it will work with grayscale frames /// The video writer //[SuppressUnmanagedCodeSecurity] [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public static extern IntPtr cvCreateVideoWriter([MarshalAs(UnmanagedType.LPStr)] String filename, int fourcc, double fps, Size frameSize, [MarshalAs(UnmanagedType.Bool)] bool isColor); /// /// Writes/appends one frame to video file. /// /// video writer structure. /// the written frame /// True on success, false otherwise //[SuppressUnmanagedCodeSecurity] [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool cvWriteFrame(IntPtr writer, IntPtr image); /// /// Finishes writing to video file and releases the structure. /// /// pointer to video file writer structure //[SuppressUnmanagedCodeSecurity] [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public static extern void cvReleaseVideoWriter(ref IntPtr writer); #endregion #region Image IO //[SuppressUnmanagedCodeSecurity] [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern IplImage* cvLoadImage([MarshalAs(UnmanagedType.LPStr)] String filename, ImageLoadType loadType); //[SuppressUnmanagedCodeSecurity] [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern bool cvSaveImage([MarshalAs(UnmanagedType.LPStr)] String filename, IplImage* image, IntPtr parameters); public const int CV_IMWRITE_JPEG_QUALITY = 1; public const int CV_IMWRITE_PNG_COMPRESSION = 16; public const int CV_IMWRITE_PXM_BINARY = 32; [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern CvMat* cvEncodeImage([MarshalAs(UnmanagedType.LPStr)] string ext, CvMat* image, int* parameters = null); [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern CvMat* cvDecodeImageM(void* buffer, ImageLoadType loadType); #endregion Image IO } } ================================================ FILE: Source/IO/IO.csproj ================================================  x64 DotImaging.IO DotImaging true bin\DotImaging.IO.xml true 5.3.0 DotImaging.IO Loading and saving images and image streams (file, in-memory, camera, video, directory). image-encode, image-decode, image-load, image-save, image-directory, camera-capture, multiple-camera-capture, video-capture, video-write Darko Jurić Darko Jurić https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Licence.txt https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Logo/logo-small.png https://raw.githubusercontent.com/dajuric/dot-imaging/ https://raw.githubusercontent.com/dajuric/dot-imaging/ true ../../Deploy/NuGet/bin/ Readme.txt runtimes\win10-x64\%(FileName)%(Extension) Always runtimes/win10-x64/native/ runtimes\ubuntu.16.04-x64\%(FileName)%(Extension) Always runtimes/ubuntu.16.04-x64/native/ ================================================ FILE: Source/IO/ImageIO.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; namespace DotImaging { /// /// Provides methods for image saving and loading /// public static class ImageIO { #region Load (file) private unsafe static IImage load(string fileName, ImageLoadType imageLoadType) { var iplImagePtr = CvInvoke.cvLoadImage(fileName, imageLoadType); var image = (*iplImagePtr).AsImage((_) => { if (iplImagePtr == null) return; CvInvoke.cvReleaseImage(ref iplImagePtr); }); return image; } /// /// Loads an image with the specified path and name as it is. /// /// Image file name. /// Image. public unsafe static IImage LoadUnchanged(this string fileName) { return load(fileName, ImageLoadType.Unchanged); } /// /// Loads an image with the specified path and name and performs and RGB conversion. /// /// Image filename. /// Image. public unsafe static Bgr[,] LoadColor(this string fileName) { Bgr[,] im = null; using (var uIm = load(fileName, ImageLoadType.Color) as Image>) im = uIm.Clone(); return im; } /// /// Loads an image with the specified path and name and performs and gray conversion. /// /// Image filename. /// Image. public unsafe static Gray[,] LoadGray(this string fileName) { Gray[,] im = null; using (var uIm = load(fileName, ImageLoadType.Grayscale) as Image>) im = uIm.Clone(); return im; } #endregion #region Save (file) /// /// Saves the provided image. If the image has non-supported color or depth false value is returned. /// /// Image to save. /// Filename. /// True if the image is saved, false otherwise. public unsafe static bool TrySave(IImage image, string fileName) { IplImage iplImage = default(IplImage); try { iplImage = image.AsCvIplImage(); } catch { return false; } CvInvoke.cvSaveImage(fileName, &iplImage, IntPtr.Zero); return true; } /// /// Saves the specified image. /// /// Image color. /// Image to save. /// Image filename. private unsafe static void Save(this Image image, string fileName) where TColor : unmanaged, IColor { var iplImage = image.AsCvIplImage(); CvInvoke.cvSaveImage(fileName, &iplImage, IntPtr.Zero); } /// /// Saves the specified image. /// /// Image color. /// Image to save. /// Image filename. private unsafe static void Save(this TColor[,] image, string fileName) where TColor: unmanaged, IColor { using (var img = image.Lock()) { var iplImage = img.AsCvIplImage(); CvInvoke.cvSaveImage(fileName, &iplImage, IntPtr.Zero); } } #region Save-gray /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Gray[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Gray[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Gray[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Gray[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Gray[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Gray[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Gray[,] image, string fileName) { image.Save>(fileName); } #endregion #region Save-bgr /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Bgr[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Bgr[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Bgr[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Bgr[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Bgr[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Bgr[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Bgr[,] image, string fileName) { image.Save>(fileName); } #endregion #region Save-bgra /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Bgra[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Bgra[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Bgra[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Bgra[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Bgra[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Bgra[,] image, string fileName) { image.Save>(fileName); } /// /// Saves the specified image. /// /// Image to save. /// Image filename. public static void Save(this Bgra[,] image, string fileName) { image.Save>(fileName); } #endregion #endregion #region Encode /// /// Encodes the specified image into the Jpeg byte array. /// /// Image to encode. /// Jpeg quality [0..100] where 100 is the highest quality. /// Jpeg byte array. public static byte[] EncodeAsJpeg(this Gray[,] image, int jpegQuality = 95) { return encodeAsJpeg(image, jpegQuality); } /// /// Encodes the specified image into the Jpeg byte array. /// /// Image to encode. /// Jpeg quality [0..100] where 100 is the highest quality. /// Jpeg byte array. public static byte[] EncodeAsJpeg(this Bgr[,] image, int jpegQuality = 95) { return encodeAsJpeg(image, jpegQuality); } /// /// Encodes the specified image into the Jpeg byte array. /// /// Image to encode. /// Jpeg quality [0..100] where 100 is the highest quality. /// Jpeg byte array. public static byte[] EncodeAsJpeg(this Gray[,] image, int jpegQuality = 95) { return encodeAsJpeg(image, jpegQuality); } /// /// Encodes the specified image into the Jpeg byte array. /// /// Image to encode. /// Jpeg quality [0..100] where 100 is the highest quality. /// Jpeg byte array. public static byte[] EncodeAsJpeg(this Bgr[,] image, int jpegQuality = 95) { return encodeAsJpeg(image, jpegQuality); } /// /// Encodes the specified image into the PNG byte array. /// /// Image to encode. /// PNG compression level [0..9] where 9 is the highest compression. /// PNG byte array. public static byte[] EncodeAsPng(this Gray[,] image, int pngCompression = 3) { return encodeAsPng(image, pngCompression); } /// /// Encodes the specified image into the PNG byte array. /// /// Image to encode. /// PNG compression level [0..9] where 9 is the highest compression. /// PNG byte array. public static byte[] EncodeAsPng(this Bgr[,] image, int pngCompression = 3) { return encodeAsPng(image, pngCompression); } /// /// Encodes the specified image into the PNG byte array. /// /// Image to encode. /// PNG compression level [0..9] where 9 is the highest compression. /// PNG byte array. public static byte[] EncodeAsPng(this Bgra[,] image, int pngCompression = 3) { return encodeAsPng(image, pngCompression); } /// /// Encodes the specified image into the PNG byte array. /// /// Image to encode. /// PNG compression level [0..9] where 9 is the highest compression. /// PNG byte array. public static byte[] EncodeAsPng(this Gray[,] image, int pngCompression = 3) { return encodeAsPng(image, pngCompression); } /// /// Encodes the specified image into the PNG byte array. /// /// Image to encode. /// PNG compression level [0..9] where 9 is the highest compression. /// PNG byte array. public static byte[] EncodeAsPng(this Bgr[,] image, int pngCompression = 3) { return encodeAsPng(image, pngCompression); } /// /// Encodes the specified image into the PNG byte array. /// /// Image to encode. /// PNG compression level [0..9] where 9 is the highest compression. /// PNG byte array. public static byte[] EncodeAsPng(this Bgra[,] image, int pngCompression = 3) { return encodeAsPng(image, pngCompression); } /// /// Encodes the specified image into the specified image type byte array. /// /// Image to encode. /// Image type extension (.bmp, .png, .jpg) /// Image type byte array. public static byte[] Encode(this Gray[,] image, string extension) { return encode(image, extension, null); } /// /// Encodes the specified image into the specified image type byte array. /// /// Image to encode. /// Image type extension (.bmp, .png, .jpg) /// Image type byte array. public static byte[] Encode(this Bgr[,] image, string extension) { return encode(image, extension, null); } /// /// Encodes the specified image into the specified image type byte array. /// /// Image to encode. /// Image type extension (.bmp, .png, .jpg) /// Image type byte array. public static byte[] Encode(this Bgra[,] image, string extension) { return encode(image, extension, null); } /// /// Encodes the specified image into the specified image type byte array. /// /// Image to encode. /// Image type extension (.bmp, .png, .jpg) /// Image type byte array. public static byte[] Encode(this Gray[,] image, string extension) { return encode(image, extension, null); } /// /// Encodes the specified image into the specified image type byte array. /// /// Image to encode. /// Image type extension (.bmp, .png, .jpg) /// Image type byte array. public static byte[] Encode(this Bgr[,] image, string extension) { return encode(image, extension, null); } /// /// Encodes the specified image into the specified image type byte array. /// /// Image to encode. /// Image type extension (.bmp, .png, .jpg) /// Image type byte array. public static byte[] Encode(this Bgra[,] image, string extension) { return encode(image, extension, null); } static byte[] encodeAsJpeg(TColor[,] image, int jpegQuality = 95) where TColor : unmanaged, IColor { if (jpegQuality < 0 || jpegQuality > 100) throw new ArgumentOutOfRangeException("Jpeg quality must be in range: 0-100."); int[] parameters = new int[] { CvInvoke.CV_IMWRITE_JPEG_QUALITY, jpegQuality, 0 }; return encode(image, ".jpg", parameters); } static byte[] encodeAsPng(TColor[,] image, int pngCompression = 3) where TColor : unmanaged, IColor { if (pngCompression < 0 || pngCompression > 9) throw new ArgumentOutOfRangeException("Png compression must be in range: 0-9."); int[] parameters = new int[] { CvInvoke.CV_IMWRITE_PNG_COMPRESSION, pngCompression, 0 }; return encode(image, ".png", parameters); } static unsafe byte[] encode(TColor[,] image, string extension, int[] parameters) where TColor : unmanaged, IColor { CvMat* matEncoded; //a single-row image using (var uImg = image.Lock()) { fixed (int* paramsPtr = parameters) { var mat = uImg.AsCvMat(); matEncoded = CvInvoke.cvEncodeImage(extension, &mat, paramsPtr); } } byte[] imEncoded = new byte[matEncoded->Step * matEncoded->Height]; fixed (byte* arrPtr = &imEncoded[0]) { Copy.UnsafeCopy(matEncoded->ImageData, (IntPtr)arrPtr, imEncoded.Length); } CvInvoke.cvReleaseMat(ref matEncoded); //TODOD: check if this deferences the image return imEncoded; } #endregion #region Decode /// /// Decodes (and converts if necessary) an image as color image using the specified byte array. /// /// Encoded image. /// Decoded image. public unsafe static Bgr[,] DecodeAsColorImage(this byte[] encodedImage) { return decodeImage>(encodedImage, ImageLoadType.Color); } /// /// Decodes (and converts if necessary) an image as gray image using the specified byte array. /// /// Encoded image. /// Decoded image. public unsafe static Gray[,] DecodeAsGrayImage(this byte[] encodedImage) { return decodeImage>(encodedImage, ImageLoadType.Grayscale); } unsafe static TColor[,] decodeImage(byte[] encodedImage, ImageLoadType loadType) where TColor : unmanaged, IColor { CvMat* matDecoded; fixed (byte* encodedImPtr = encodedImage) { CvMat mat = CvMat.FromUserData((IntPtr)encodedImPtr, encodedImage.Length, 1, encodedImage.Length, CvMat.CvChannelDepth.CV_8U, 1); matDecoded = CvInvoke.cvDecodeImageM(&mat, ImageLoadType.Color); } var imDecoded = (*matDecoded).ToArray(); CvInvoke.cvReleaseMat(ref matDecoded); return imDecoded; } #endregion } } ================================================ FILE: Source/IO/Readers/CameraCapture.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Drawing; namespace DotImaging { /// /// Represents camera stream-able source and provides functions and properties to access a device in a stream-able way. /// public class CameraCapture: VideoCaptureBase { int cameraIdx = 0; /// /// Creates capture from camera. /// /// Camera index. public CameraCapture(int cameraIdx = 0) { this.cameraIdx = cameraIdx; this.CanSeek = false; this.IsLiveStream = true; this.Open(); //to enable property change } /// /// Opens the camera stream. /// public override void Open() { if (capturePtr != IntPtr.Zero) return; capturePtr = CvInvoke.cvCreateCameraCapture(cameraIdx); if (capturePtr == IntPtr.Zero) throw new Exception("Cannot open camera stream! It seems that camera device can not be found."); } /// /// Gets or sets the brightness of the camera. /// If the property is not supported by device 0 will be returned. /// public double Brightness { get { return CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.Brightness); } set { CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.Brightness, value); } } /// /// Gets or sets the contrast of the camera. /// If the property is not supported by device 0 will be returned. /// public double Contrast { get { return CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.Contrast); } set { CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.Contrast, value); } } /// /// Gets or sets the exposure of the camera. /// If the property is not supported by device 0 will be returned. /// public double Exposure { get { return CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.Exposure); } set { CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.Exposure, value); } } /// /// Gets or sets the gain of the camera. /// If the property is not supported by device 0 will be returned. /// public double Gain { get { return CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.Gain); } set { CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.Gain, value); } } /// /// Gets or sets the hue of the camera. /// If the property is not supported by device 0 will be returned. /// public double Hue { get { return CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.Hue); } set { CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.Hue, value); } } /// /// Gets or sets the saturation of the camera. /// If the property is not supported by device 0 will be returned. /// public double Saturation { get { return CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.Saturation); } set { CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.Saturation, value); } } /// /// Gets or sets the frame size of the camera. /// public new Size FrameSize { get { return CvInvoke.GetImageSize(capturePtr); } set { CvInvoke.SetImageSize(capturePtr, value); } } /// /// Gets or sets the frame rate of the camera. /// If the property is not supported by device 0 will be returned. /// public new double FrameRate { get { return CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.FPS); } set { CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.FPS, value); } } /// /// Gets the available device count. /// Warning: the function closes existing streams, so use it before any camera capture object is created. /// public static int CameraCount { get { int cameraIdx = 0; while (true) { var capturePtr = CvInvoke.cvCreateCameraCapture(cameraIdx); if (capturePtr != IntPtr.Zero) { CvInvoke.cvReleaseCapture(ref capturePtr); cameraIdx++; } else break; } return cameraIdx; } } } } ================================================ FILE: Source/IO/Readers/FileCapture.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.IO; using System.Linq; namespace DotImaging { /// /// Provides functions and properties to access video file in a streamable way. /// public class FileCapture: VideoCaptureBase { private static readonly string[] supportedRemoteFiles = new string[] { ".mp4", ".webm" }; private static readonly string[] supportedLocalFiles = new string[] { ".mp4", ".avi", ".divx", ".webm", ".wmv" }; string fileName = null; /// /// Creates capture from video file. /// /// /// Local file, http uri, ftp uri or a named pipe. /// In case of named pipe use: String.Format(@"\\.\pipe\{0}", pipeName) where pipeName is the name of the pipe. /// public FileCapture(string sourceName) { if (sourceName.Contains(@"\\.\pipe\")) { this.CanSeek = false; } else if (Uri.IsWellFormedUriString(sourceName, UriKind.Absolute)) { var fileExt = Path.GetExtension(sourceName); if (supportedRemoteFiles.Any(x => x.Equals(fileExt.ToLower())) == false) throw new UriFormatException(String.Format("Uri must point to a supported video file ({0}).", String.Join(", ", supportedRemoteFiles))); this.CanSeek = true; } else { if (!File.Exists(sourceName)) throw new FileNotFoundException(String.Format("The file {0} can not be found.", sourceName)); var fileExt = Path.GetExtension(sourceName); if (supportedLocalFiles.Any(x => x.Equals(fileExt.ToLower())) == false) throw new UriFormatException(String.Format("File must be a supported video file ({0}).", String.Join(", ", supportedLocalFiles))); this.CanSeek = true; } this.fileName = sourceName; this.Open(); //to enable property change } /// /// Opens the video file stream. /// public override void Open() { if (capturePtr != IntPtr.Zero) return; capturePtr = CvInvoke.cvCreateFileCapture(fileName); if (capturePtr == IntPtr.Zero) throw new Exception("Cannot open FileStream!"); } /// /// Gets the current position in the stream as frame offset. /// public override long Position { get { return (long)CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.PosFrames); } protected set { } } /// /// Sets the position within the current stream. /// Warning: the underlying OpenCV function seeks to nearest key-frame, therefore the seek operation may not be frame-accurate. /// /// A frame index offset relative to the origin parameter. /// A value of type System.IO.SeekOrigin indicating the reference point used to obtain the new position. /// The new position within the current stream. public override long Seek(long offset, System.IO.SeekOrigin origin = SeekOrigin.Current) { var frameIndex = base.Seek(offset, origin); CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.PosFrames, frameIndex); return Position; } } } ================================================ FILE: Source/IO/Readers/ImageDirectoryCapture.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace DotImaging { /// /// Represents directory stream-able source and provides functions and properties to access data in a stream-able way. /// public class ImageDirectoryCapture : ImageStreamReader { long currentFrame = 0; #region Initialization /// /// Creates an instance of . /// /// The directory path. /// The image search pattern. /// Use natural sorting, otherwise raw image order is used. /// If true searches the current directory and all subdirectories. Otherwise, only top directory is searched. /// Directory can not be found. public ImageDirectoryCapture(string dirPath, string searchPattern, bool useNaturalSorting = true, bool recursive = false) : this(dirPath, new string[] { searchPattern }, useNaturalSorting, recursive) { } /// /// Creates an instance of . /// /// The directory path. /// The image search patterns. /// Use natural sorting, otherwise raw image order is used. /// If true searches the current directory and all subdirectories. Otherwise, only top directory is searched. /// Directory can not be found. public ImageDirectoryCapture(string dirPath, string[] searchPatterns, bool useNaturalSorting = true, bool recursive = false) { FileReadFunction = ImageIO.LoadUnchanged; if (Directory.Exists(dirPath) == false) throw new DirectoryNotFoundException(String.Format("Dir: {0} cannot be found!", dirPath)); DirectoryInfo directoryInfo = new DirectoryInfo(dirPath); this.IsLiveStream = false; this.CanSeek = true; this.DirectoryInfo = directoryInfo; var searchOption = recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; if (useNaturalSorting) { this.FileInfos = directoryInfo.EnumerateFiles(searchPatterns, searchOption) .OrderBy(f => f.FullName, new NaturalSortComparer()) //in case of problems replace f.FullName with f.Name .ToArray(); } else { this.FileInfos = directoryInfo.EnumerateFiles(searchPatterns, searchOption) .ToArray(); } } #endregion /// /// Open the current stream. This overload does not do anything. /// public override void Open() { } /// /// Closes the current stream. This overload resets position to zero. /// public override void Close() { currentFrame = 0; } object syncObj = new object(); /// /// Reads an image from the stream. /// /// Read image. /// True if the reading operation was successful, false otherwise. protected override bool ReadInternal(out IImage image) { lock (syncObj) { image = default(IImage); if (this.Position >= this.Length) return false; image = FileReadFunction(FileInfos[currentFrame].FullName); currentFrame++; } return true; } /// /// Gets the total number of files in the specified directory which match the specified search criteria. /// public override long Length { get { return FileInfos.Length; } } /// /// Gets the current position within the stream. /// public override long Position { get { return currentFrame; } } /// /// Sets the position within the current stream. /// /// A frame index offset relative to the origin parameter. /// A value of type indicating the reference point used to obtain the new position. /// The new position within the current stream. public override long Seek(long offset, SeekOrigin origin = SeekOrigin.Current) { this.currentFrame = base.Seek(offset, origin); return Math.Max(0, Math.Min(currentFrame, this.Length)); } #region Specific function /// /// Gets the source directory info. /// public DirectoryInfo DirectoryInfo { get; private set; } /// /// Gets the ordered set of files which compose the current image directory stream. /// public FileInfo[] FileInfos { get; private set; } /// /// Gets the current image file name. /// If the position of the stream is equal to the stream length null is returned. /// public string CurrentImageName { get { return (this.Position < FileInfos.Length) ? FileInfos[this.Position].FullName : null; } } Func fileReadFunction; /// /// Gets or sets the file read function. /// A default reading function loads image as it is (unchanged). /// public Func FileReadFunction { get { return fileReadFunction; } set { if (value == null) new ArgumentNullException("File read function can not be null."); fileReadFunction = value; } } #endregion } } ================================================ FILE: Source/IO/Readers/VideoCaptureBase.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Drawing; namespace DotImaging { /// /// Represents the base class for video capture that shares common functions and properties with camera and file capture. /// public abstract class VideoCaptureBase : ImageStreamReader { /// /// Internal OpenCV pointer for the capture object. /// protected IntPtr capturePtr; /// /// Releases all resources allocated by capture. /// public override void Close() { if (capturePtr != IntPtr.Zero) CvInvoke.cvReleaseCapture(ref capturePtr); } object syncObj = new object(); /// /// Reads the next image in the stream and advances the position by one. /// /// Read image. /// True if the reading operation was successful, false otherwise. protected override bool ReadInternal(out IImage image) { bool status = false; image = default(IImage); lock (syncObj) { IntPtr cvFramePtr; cvFramePtr = CvInvoke.cvQueryFrame(capturePtr); if (cvFramePtr != IntPtr.Zero) { image = IplImage.FromPointer(cvFramePtr).AsImage(); this.Position++; status = true; } } return status; } /// /// Gets the length in number of frames. /// public override long Length { get { return (long)CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.FrameCount); } } /// /// Gets or sets whether to force conversion of an input image to Bgr color type. /// public bool ConvertRgb { get { return (int)CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.ConvertRGB) != 0; } set { CvInvoke.cvSetCaptureProperty(capturePtr, CaptureProperty.ConvertRGB, value ? 0 : 1); } } /// /// Gets the frame size. /// public Size FrameSize { get { return CvInvoke.GetImageSize(capturePtr); } } /// /// Gets the frame rate. /// public float FrameRate { get { return (float)CvInvoke.cvGetCaptureProperty(capturePtr, CaptureProperty.FPS); } } } } ================================================ FILE: Source/IO/Utilities/NaturalSortComparer.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Collections.Generic; using System.Text.RegularExpressions; namespace DotImaging { /// /// Provides functions for natural string comparison. /// Reference: . /// class NaturalSortComparer: IComparer { private bool isAscending; /// /// Creates a new instance of . /// /// Sorts in ascending order, otherwise descending. public NaturalSortComparer(bool inAscendingOrder = true) { this.isAscending = inAscendingOrder; } #region IComparer Members /// /// Compares two strings. /// /// First string. /// Second string. /// 0 - the same objects, -1, +1 otherwise depending whether the first string precedes the second one or not. public int Compare(string x, string y) { throw new NotImplementedException(); } #endregion #region IComparer Members int IComparer.Compare(string x, string y) { if (x == y) return 0; string[] x1, y1; if (!table.TryGetValue(x, out x1)) { x1 = Regex.Split(x.Replace(" ", ""), "([0-9]+)"); table.Add(x, x1); } if (!table.TryGetValue(y, out y1)) { y1 = Regex.Split(y.Replace(" ", ""), "([0-9]+)"); table.Add(y, y1); } int returnVal; for (int i = 0; i < x1.Length && i < y1.Length; i++) { if (x1[i] != y1[i]) { returnVal = PartCompare(x1[i], y1[i]); return isAscending ? returnVal : -returnVal; } } if (y1.Length > x1.Length) { returnVal = 1; } else if (x1.Length > y1.Length) { returnVal = -1; } else { returnVal = 0; } return isAscending ? returnVal : -returnVal; } private static int PartCompare(string left, string right) { int x, y; if (!int.TryParse(left, out x)) return left.CompareTo(right); if (!int.TryParse(right, out y)) return left.CompareTo(right); return x.CompareTo(y); } #endregion private Dictionary table = new Dictionary(); } } ================================================ FILE: Source/IO/Utilities/PathExtensions.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Collections.Generic; using System.IO; namespace DotImaging { /// /// Defined functions can be used as object extensions. /// Provides methods for string which is treated as file and directory path. /// static class PathExtensions { /// /// Returns an enumerable collection of file information that matches a specified search pattern and search subdirectory option. /// /// Directory info. /// The search strings (e.g. new string[]{ ".jpg", ".bmp" } /// /// One of the enumeration values that specifies whether the search operation /// should include only the current directory or all subdirectories. The default /// value is . /// /// An enumerable collection of files that matches and . public static IEnumerable EnumerateFiles(this DirectoryInfo dirInfo, string[] searchPatterns, SearchOption searchOption = SearchOption.TopDirectoryOnly) { var fileInfos = new List(); foreach (var searchPattern in searchPatterns) { var dirFileInfos = dirInfo.EnumerateFiles(searchPattern, searchOption); fileInfos.AddRange(dirFileInfos); } return fileInfos; } } } ================================================ FILE: Source/IO/Writers/ImageWriterExtension.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.IO; namespace DotImaging { /// /// Provides extensions for image extraction from image streams. /// public static class ImageWriterExtension { /// /// Reads the image source and save the extracted images to the specified folder. /// /// Image stream reader. /// Output directory. /// Image file name format. /// Progress function executed after a frame is saved. public static void SaveFrames(this ImageStreamReader imageSource, string outputDir, string fileNameFormat = "img-{0:000}.png", Action onFrameCompletition = null) { if (!Directory.Exists(outputDir)) Directory.CreateDirectory(outputDir); if (imageSource.CanSeek) imageSource.Seek(0, SeekOrigin.Begin); var idx = 0; foreach (var frame in imageSource) //use video stream as IEnumerable (must support seek operation) { if (frame != null) //some videos skip key frames (discard those frames) { var path = Path.Combine(outputDir, String.Format(fileNameFormat, idx)); ImageIO.TrySave(frame, path); //TODO-noncritical: add compression options } if(onFrameCompletition != null) onFrameCompletition((float)(idx + 1) / imageSource.Length); idx++; } } } } ================================================ FILE: Source/IO/Writers/VideoWriter.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Drawing; namespace DotImaging { /// /// Video writer that writes images into video file. /// public class VideoWriter : ImageStreamWriter { object syncObj = new object(); IntPtr videoObjPtr = IntPtr.Zero; /// /// Gets the output file name. /// public string OutputFileName { get; private set; } /// /// Gets whether the frame must consist of 3-channels (color) or from just one (grayscale). /// public bool ColorFrames { get; private set; } /// /// Gets the codec used to encode frames. /// public VideoCodec Codec { get; private set; } /// /// Gets the number of frames per second. /// public float FrameRate { get; private set; } /// /// Gets the frame size. /// public Size FrameSize { get; private set; } /// /// Creates new video writer (with default codec). /// /// Video file name. /// Video frame size. /// Specifies the number of frames per second. /// Specifies whether the image is color image (3 channels) or grayscale image (one channel). public VideoWriter(string fileName, Size frameSize, float fps = 30, bool isColor = true) : this(fileName, frameSize, fps, isColor, VideoCodec.MotionJpeg) { } /// /// Creates new video writer. /// /// Video file name. /// Video frame size. /// Specifies the number of frames per second. /// Specifies whether the image is color image (3 channels) or grayscale image (one channel). /// Specifies used codec for video encoding. public VideoWriter(string fileName, Size frameSize, float fps, bool isColor, VideoCodec videoCodec) { this.CanSeek = false; this.IsLiveStream = true; this.OutputFileName = fileName; this.ColorFrames = isColor; this.Codec = videoCodec; this.FrameSize = frameSize; this.FrameRate = fps; this.Open(); //to enable property change } /// /// Opens the video file stream. /// public override void Open() { if (videoObjPtr != IntPtr.Zero) return; videoObjPtr = CvInvoke.cvCreateVideoWriter(OutputFileName, (int)Codec, FrameRate, FrameSize, ColorFrames); if (videoObjPtr == IntPtr.Zero) throw new Exception(String.Format("Cannot open FileStream! Please check that the selected codec ({0}) is supported.", Codec)); } /// /// Gets the current position in the stream as frame offset. /// public override long Position { get; protected set; } /// /// Gets the current stream length which is not constant and is the same as position. /// public override long Length { get { return this.Position; } } /// /// Writes the provided image to the stream. /// /// Image to write. /// True, if the operation was successful, false otherwise. protected unsafe override bool WriteInternal(IImage image) { bool isSuccessful; lock (syncObj) { if (image.ColorInfo.ChannelCount == 3 && !ColorFrames) throw new Exception("Image must be grayscale!"); if (image.ColorInfo.ChannelCount == 1 && ColorFrames) throw new Exception("Image must be color!"); if (image.ColorInfo.ChannelCount != 3 && ColorFrames) throw new Exception("Color images must have 3 channels!"); if (!image.Size.Equals(FrameSize)) throw new Exception("Input image must be the same size as defined frame size!"); this.Position++; var iplImg = image.AsCvIplImage(); IplImage* iplImgPtr = (IplImage*)&iplImg; isSuccessful = CvInvoke.cvWriteFrame(videoObjPtr, (IntPtr)iplImgPtr); } return isSuccessful; } /// /// Closes video writer. /// Use dispose method to remove any additional resources. /// public override void Close() { if (videoObjPtr != IntPtr.Zero) CvInvoke.cvReleaseVideoWriter(ref videoObjPtr); } } } ================================================ FILE: Source/IO.Web/.nuSpec/readmeIO.Web.txt ================================================  Provides support for image or video download/streaming (direct video link or Youtube links). 1) image loading: new Uri("http://vignette3.wikia.nocookie.net/disney/images/5/5d/Lena_headey_.jpg") .GetBytes() .DecodeAsColorImage() .Show(); //requires UI package 2) video streaming: var sourceName = String.Empty; var pipeName = new Uri("https://www.youtube.com/watch?v=Vpg9yizPP_g").NamedPipeFromYoutubeUri(); //Youtube sourceName = String.Format(@"\\.\pipe\{0}", pipeName); //sourceName = "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"; //direct http streaming //------------------------------------------------------------------ ImageStreamReader reader = new FileCapture(sourceName); reader.Open(); //seek if you can if(reader.CanSeek) reader.Seek((int)(reader.Length * 0.25), System.IO.SeekOrigin.Begin); //read video frames Bgr[,] frame = null; do { reader.ReadTo(ref frame); if (frame == null) break; frame.Show(scaleForm: true); ((double)reader.Position / reader.Length).Progress(); } while (!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape)); 3) video download: string fileExtension; pipeName = new Uri("https://www.youtube.com/watch?v=Vpg9yizPP_g").NamedPipeFromYoutubeUri(out fileExtension); //Youtube pipeName.SaveNamedPipeStream("out" + fileExtension); Discover more types as you type :) ================================================ FILE: Source/IO.Web/IO.Web.csproj ================================================  DotImaging.IO.Web DotImaging AnyCPU bin\DotImaging.IO.Web.xml true 5.3.0 DotImaging.IO.Web Image or video download/streaming (direct video link or Youtube links). web-image, image-download, video-download, video-streaming, Youtube, web-video Darko Jurić Darko Jurić https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Licence.txt https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Logo/logo-small.png https://raw.githubusercontent.com/dajuric/dot-imaging/ https://raw.githubusercontent.com/dajuric/dot-imaging/ true ../../Deploy/NuGet/bin/ Readme.txt ================================================ FILE: Source/IO.Web/NamedPipeExtensions.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.IO; using System.Threading.Tasks; using System.IO.Pipes; using System.Net; using VideoLibrary; namespace DotImaging { /// /// Provides named pipe creation extension for Uri, string and Stream. /// public static class NamedPipeExtensions { #region Reading /// /// Creates a new named pipe from a file stream. /// /// File name. /// Named pipe. /// Function executed when progress changes. Return true to cancel the operation, false to continue. /// Pipe name. public static string NamedPipeFromFileName(this string fileName, string namedPipeName = "filePipe", Func onProgress = null) { if (File.Exists(fileName)) throw new ArgumentException("The provided file does not exist.", nameof(fileName)); Stream source = File.OpenRead(fileName); return NamedPipeFromStreamAsync(source, namedPipeName, onProgress, () => { source.Dispose(); }); } /// /// Creates a new named pipe from a link (video-link if used in conjunction with IO package). /// /// Uri to web file. /// Named pipe. /// Function executed when progress changes. Return true to cancel the operation, false to continue. /// Pipe name. public static string NamedPipeFromVideoUri(this Uri uri, string namedPipeName = "webPipe", Func onProgress = null) { var request = (HttpWebRequest)WebRequest.Create(uri.AbsoluteUri); WebResponse response = request.GetResponse(); Stream source = response.GetResponseStream(); return NamedPipeFromStreamAsync(source, namedPipeName, onProgress, () => { source.Dispose(); response.Dispose(); }); } /// /// Creates a new named pipe from a Youtube video link. /// /// Uri to Youtube video file. /// Video-file extension. /// Named pipe. /// Function executed when progress changes. Return true to cancel the operation, false to continue. /// Pipe name. public static string NamedPipeFromYoutubeUri(this Uri youtubeUri, out string fileExtension, string namedPipeName = "youtubeVideoPipe", Func onProgress = null) { if (youtubeUri.Host != "www.youtube.com") throw new ArgumentException("The provided URI is not valid Youtube URI."); var youtubeVideo = YouTube.Default.GetVideo(youtubeUri.AbsoluteUri); fileExtension = youtubeVideo.FileExtension; VideoClient vc = new VideoClient(); Stream source = vc.Stream(youtubeVideo); return NamedPipeFromStreamAsync(source, namedPipeName, onProgress, () => { source.Dispose(); vc.Dispose(); }); } /// /// Creates a new named pipe from a Youtube video link. /// /// Uri to Youtube video file. /// Named pipe. /// Function executed when progress changes. Return true to cancel the operation, false to continue. /// Pipe name. public static string NamedPipeFromYoutubeUri(this Uri youtubeUri, string namedPipeName = "youtubeVideoPipe", Func onProgress = null) { string fileExtension; return NamedPipeFromYoutubeUri(youtubeUri, out fileExtension, namedPipeName, onProgress); } /// /// Creates a new named pipe from a Youtube video link. /// /// Source stream. /// Named pipe. /// Function executed when progress changes. Return true to cancel the operation, false to continue. /// Action executed when a reading operation finishes. /// Pipe name. public static string NamedPipeFromStreamAsync(this Stream source, string namedPipeName, Func onProgress = null, Action onFinish = null) { if (source == null) new ArgumentNullException(nameof(source)); Task.Factory.StartNew(() => { using (NamedPipeServerStream target = new NamedPipeServerStream(namedPipeName)) { target.WaitForConnection(); target.WaitForPipeDrain(); int bytes, copiedBytes = 0; var buffer = new byte[1024]; while ((bytes = source.Read(buffer, 0, buffer.Length)) > 0) { target.Write(buffer, 0, bytes); copiedBytes += bytes; if (onProgress != null) { bool shouldCancel = onProgress((float)copiedBytes / source.Length); if (shouldCancel) break; } } target.Flush(); if (onFinish != null) onFinish(); } }); return namedPipeName; } #endregion #region Writing /// /// Copies the named pipe stream to the specified stream. /// /// Pipe name. /// Destination stream. public static void CopyNamedPipeStream(this string pipeName, Stream target) { using (NamedPipeClientStream clientPipe = new NamedPipeClientStream(pipeName)) { clientPipe.Connect(); int bytes, copiedBytes = 0; var buffer = new byte[1024]; while ((bytes = clientPipe.Read(buffer, 0, buffer.Length)) > 0) { target.Write(buffer, 0, bytes); copiedBytes += bytes; /*if (onProgress != null) { bool shouldCancel = onProgress((float)copiedBytes / clientPipe.Length); if (shouldCancel) break; }*/ } target.Flush(); } } /// /// Saves the named pipe stream to the specified file. /// /// Pipe name. /// Destination file. public static void SaveNamedPipeStream(this string pipeName, string targetFile) { using (Stream target = File.Create(targetFile)) { CopyNamedPipeStream(pipeName, target); } } #endregion } } ================================================ FILE: Source/IO.Web/WebImageExtensions.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.IO; using System.Net; namespace DotImaging { /// /// Provides extensions for getting images from the Web. /// public static class WebImageExtensions { /// /// Gets the bytes from the Web using the specified uri. /// /// File Web location. /// Function executed when progress changes. Return true to cancel the operation, false to continue. /// Encoded image or undefined output in case if the operation is canceled. public static byte[] GetBytes(this Uri uri, Func onProgress = null) { byte[] output = null; var request = (HttpWebRequest)WebRequest.Create(uri.AbsoluteUri); using (WebResponse response = request.GetResponse()) using (Stream source = response.GetResponseStream()) using(MemoryStream target = new MemoryStream()) { int bytes, copiedBytes = 0; var buffer = new byte[1024]; while ((bytes = source.Read(buffer, 0, buffer.Length)) > 0) { target.Write(buffer, 0, bytes); copiedBytes += bytes; if (onProgress != null) { bool shouldCancel = onProgress((float)copiedBytes / response.ContentLength); if (shouldCancel) break; } } target.Flush(); output = target.ToArray(); } return output; } } } ================================================ FILE: Source/Image/.nuSpec/readmeImage.txt ================================================ Provides .NET native array imaging extensions. Color-spaces and channel depth conversion is included. Implements slim generic image class when fast pixel manipulation is needed. To get compatibility for other image types install appropriate extension - NuGet package (e.g. Imaging.BitmapInterop). 1) Color and depth conversion: Bgr[,] image = ImageIO.LoadColor("sample.jpg"); //requires DotImaging.IO package Gray grayFloatIm = image.ToGray() .Cast(); 2) Splitting and merging channels: Bgra[,] image = new Bgra[480, 640]; Gray[][,] channels = image.SplitChannels(0, 1, 2); //take B, G and R channel Bgr bgrIm = channels.MergeChannels, byte>(); 3) Unsafe operations: Bgr[,] image = new Bgr[240, 320]; using(var unmanagedImage = image.Lock()) //create unmanaged structure that shares data with the array { Bgr8* ptr = (Bgr8*)unmanagedImage.GetData(10, 10); ptr->B = 111; } 4) OpenCV compatibility: Gray[,] image = new Gray[240, 320]; IplImage iplIm = image.AsOpenCvImage(); //to OpenCV image Gray[,] imFromIpl = iplIm.AsImage().Clone(); //to array 5) LINQ: Bgr[,] image = ImageIO.LoadColor("sample.jpg").Clone(); //get the modified blue channel var modifiedImage = image.AsEnumerable() .Select(x => x.B / 2) .ToArray2D(image.Size()); 6) Misc Hsv[,] image = new Hsv[240, 320]; image.SetValue(new Hsv(10, 10, 255)); //set pixels value Console.WriteLine(image.Size()); //write image size Console.WriteLine(image.ColorInfo()); //write color info ... Discover more extensions as you type :) ================================================ FILE: Source/Image/ColorTypeConversions/ColorInfo.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Collections.Concurrent; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; namespace DotImaging { /// /// Gets color information from color type and depth type. /// public class ColorInfo: IEquatable { static ConcurrentDictionary colorInfos = new ConcurrentDictionary(); /// /// Color type (IColor). /// public Type ColorType { get; private set; } /// /// Number of channels that color has. /// public int ChannelCount { get; private set; } /// /// Number of bytes per channel. /// public int ChannelSize { get; private set; } /// /// Channel type. Only primitive types are supported. /// public Type ChannelType { get; private set; } /// /// Color size in bytes. Number of channels multiplied by channel size. /// public int Size { get { return this.ChannelSize * this.ChannelCount; } } /// /// Gets color info (depth is taken from color). /// /// Member of /// Color info public static ColorInfo GetInfo() //where TColor : IColor { return GetInfo(typeof(TColor)); } /// /// Gets color info (depth is taken from color). /// /// Color type. (member of IColor) /// Color info public static ColorInfo GetInfo(Type colorType) { return colorInfos.GetOrAdd(colorType, getInfo); } private static ColorInfo getInfo(Type colorType) { ColorInfo ci = new ColorInfo(); ci.ColorType = colorType; Type channelType; int numberOfChannels; getChannelInfo(colorType, out channelType, out numberOfChannels); ci.ChannelCount = numberOfChannels; ci.ChannelType = channelType; ci.ChannelSize = Marshal.SizeOf(channelType); return ci; } private static void getChannelInfo(Type colorType, out Type channelType, out int numberOfChannels) { numberOfChannels = 0; var channelTypes = colorType .GetFields(BindingFlags.Public | ~BindingFlags.Static) //if BindingFlags.Instance and if colorType is byte => zero length array .Select(x => x.FieldType) .ToArray(); //ensure that all types are the same var _channelType = channelTypes[0]; if (channelTypes.Where(x => x.Equals(_channelType)).Count() != channelTypes.Length) throw new Exception("Public fields must have the same type!"); if (channelTypes.Length == 0) throw new Exception("Color structure must have at least one public field!"); if (!_channelType.IsValueType) throw new Exception("Channel type must be a value type!"); if (!_channelType.IsPrimitive) throw new Exception("Channel type must be a primitive type!"); channelType = _channelType; numberOfChannels = channelTypes.Length; } /// /// Determines whether the object is equal compared to the specified object. /// A default comparison is used. Please see overloads. /// /// Other object. /// True if two objects are equal, false otherwise. public bool Equals(ColorInfo other) { return Equals(other, ComparableParts.Default); } /// /// Indicates what parts of color info should be compared. /// [Flags] public enum ComparableParts { /// /// Checks color depth type /// Depth = 0x1, /// /// Checks if one color can be casted to other (if colors are binary compatible). /// BinaryCompatible = 0x3, /// /// Checks color type and depth type (if it is true all other properties are equal as well) /// Default = 0x4 } /// /// Compares two color infos. /// /// Other color info. /// Indicates what to compare. Default is: ComparableParts.Default. /// public bool Equals(ColorInfo other, ComparableParts cParts) { if(cParts == ComparableParts.Default) { return this.ColorType == other.ColorType && this.ChannelType == other.ChannelType; } if (cParts == ComparableParts.BinaryCompatible) { var castable = (this.ChannelCount == other.ChannelCount) && (this.ChannelType == other.ChannelType); return castable; } if (cParts == ComparableParts.Depth) { var depth = this.ChannelType == other.ChannelType; return depth; } throw new Exception("Unknown comparison!"); } /// /// Get string representation. /// /// String public override string ToString() { return String.Format("<{0}, {1}>", this.ColorType.Name, this.ChannelType.Name); } } /// /// Provides extensions for color to array conversion. /// public static class ColorToArrayExtensions { /// /// Converts color to array of type . /// /// Color type. /// Channel type. /// Color /// Array whose length is the same as color's number of channels. public static TDepth[] ColorToArray(this TColor color) where TColor : IColor where TDepth : struct { var fields = typeof(TColor).GetFields(BindingFlags.Public | ~BindingFlags.Static); TDepth[] arr = new TDepth[fields.Length]; for (int i = 0; i < fields.Length; i++) { var rawVal = fields[i].GetValue(color); arr[i] = (TDepth)Convert.ChangeType(rawVal, typeof(TDepth)); } return arr; } } } ================================================ FILE: Source/Image/ColorTypeConversions/ColorSpaces/Bgr.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace DotImaging { /// /// Represents Bgr color type of type color depth. /// [StructLayout(LayoutKind.Sequential)] public struct Bgr : IColor3 where T : unmanaged { /// /// Creates new Bgr color. /// /// Blue /// Green /// Red public Bgr(T b, T g, T r) { this.B = b; this.G = g; this.R = r; } /// /// Gets or sets the blue component. /// public T B; /// /// Gets or sets the green component. /// public T G; /// /// Gets or sets the red component. /// public T R; /// /// Gets the string color representation. /// /// String color representation. public override string ToString() { return string.Format("B: {0}, G: {1}, R: {2}", B, G, R); } /// /// Gets the index of the blue component. /// public const int IdxB = 0; /// /// Gets the index of the green component. /// public const int IdxG = 1; /// /// Gets the index of the red component. /// public const int IdxR = 2; /// /// Gets the 8-bit red color. /// public static Bgr Red { get { return new Bgr { B = 0, G = 0, R = byte.MaxValue }; } } /// /// Gets the 8-bit blue color. /// public static Bgr Blue { get { return new Bgr { B = byte.MaxValue, G = 0, R = 0 }; } } /// /// Gets the 8-bit green color. /// public static Bgr Green { get { return new Bgr { B = 0, G = byte.MaxValue, R = 0 }; } } /// /// Gets the 8-bit black color. /// public static Bgr Black { get { return new Bgr { B = 0, G = 0, R = 0 }; } } /// /// Gets the 8-bit white color. /// public static Bgr White { get { return new Bgr { B = byte.MaxValue, G = byte.MaxValue, R = byte.MaxValue }; } } /// /// Converts 8-bit Bgr to 8-bit gray intensity. /// /// Source color. /// Destination color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Convert(Bgr bgr, ref Gray gray) { int val = ((bgr.R << 1) + //2 * red (bgr.G << 2) + bgr.G + //5 * green bgr.B //1 * blue ) >> 3; //divide by 8 gray.Intensity = (byte)val; } /// /// Converts 8-bit Bgr to 8-bit Bgra. /// /// Source color. /// Destination color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Convert(Bgr bgr, ref Bgra bgra) { bgra.B = bgr.B; bgra.G = bgr.G; bgra.R = bgr.R; bgra.A = System.Byte.MaxValue; } /// /// Converts 8-bit Bgr to 8-bit Bgra. /// /// Source color. /// Destination color. /// Opacity. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Convert(Bgr bgr, ref Bgra bgra, byte opacity = System.Byte.MaxValue) { bgra.B = bgr.B; bgra.G = bgr.G; bgra.R = bgr.R; bgra.A = opacity; } /// /// Converts 8-bit Bgr to 8-bit Hsv color. Value range for 8-bit HSv color is [0..180]. /// /// Source color. /// Destination color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Convert(Bgr bgr, ref Hsv hsv) { byte rgbMin, rgbMax; rgbMin = bgr.R < bgr.G ? (bgr.R < bgr.B ? bgr.R : bgr.B) : (bgr.G < bgr.B ? bgr.G : bgr.B); rgbMax = bgr.R > bgr.G ? (bgr.R > bgr.B ? bgr.R : bgr.B) : (bgr.G > bgr.B ? bgr.G : bgr.B); hsv.V = rgbMax; if (hsv.V == 0) { hsv.H = 0; hsv.S = 0; return; } hsv.S = (byte)(255 * (rgbMax - rgbMin) / rgbMax); if (hsv.S == 0) { hsv.H = 0; return; } int hue = 0; if (rgbMax == bgr.R) { hue = 0 + 60 * (bgr.G - bgr.B) / (rgbMax - rgbMin); if (hue < 0) hue += 360; } else if (rgbMax == bgr.G) { hue = 120 + 60 * (bgr.B - bgr.R) / (rgbMax - rgbMin); } else //rgbMax == bgr.B { hue = 240 + 60 * (bgr.R - bgr.G) / (rgbMax - rgbMin); } hsv.H = (byte)(hue / 2); //scale [0-360] . [0-180] (only needed for byte!) //Debug.Assert(hue >= 0 && hue <= 360); } } /// /// Provides extension conversion methods for 8-bit Bgr type. /// public static class BgrColorConversionExtensions { /// /// Converts 8-bit Bgr color to 8-bit gray. /// /// 8-bit Bgr color. /// 8-bit gray [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Gray ToGray(this Bgr bgr) { Gray gray = default(Gray); Bgr.Convert(bgr, ref gray); return gray; } /// /// Converts 8-bit Bgr color to 8-bit Hsv color. /// /// 8-bit Bgr color. /// 8-bit Hsv color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Hsv ToHsv(this Bgr bgr) { Hsv hsv = default(Hsv); Bgr.Convert(bgr, ref hsv); return hsv; } } /// /// Represents 8-bit Bgr color type. /// Its usage should be restricted only for unsafe pixel manipulation. /// public struct Bgr8 { /// /// Gets or sets the blue component. /// public byte B; /// /// Gets or sets the green component. /// public byte G; /// /// Gets or sets the red component. /// public byte R; } } ================================================ FILE: Source/Image/ColorTypeConversions/ColorSpaces/Bgra.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Runtime.InteropServices; namespace DotImaging { /// /// Represents Bgra color type of type depth. /// [StructLayout(LayoutKind.Sequential)] public struct Bgra : IColor4 where T: unmanaged { /// /// Creates new Bgra color. /// /// Blue /// Green /// Red /// Alpha (transparency). public Bgra(T b, T g, T r, T a) { this.B = b; this.G = g; this.R = r; this.A = a; } /// /// Gets or sets the blue component. /// public T B; /// /// Gets or sets the green component. /// public T G; /// /// Gets or sets the red component. /// public T R; /// /// Gets or sets the alpha component. /// public T A; /// /// Gets the string color representation. /// /// String color representation. public override string ToString() { return string.Format("B: {0}, G: {1}, R: {2}, A: {3}", B, G, R, A); } /// /// Gets the index of the blue component. /// public const int IdxB = 0; /// /// Gets the index of the green component. /// public const int IdxG = 1; /// /// Gets the index of the red component. /// public const int IdxR = 2; /// /// Gets the index of the alpha component. /// public const int IdxA = 3; /// /// Converts 8-bit Bgra to 8-bit Bgr color. /// /// Source color. /// Destination color. public static void Convert(Bgra bgra, ref Bgr bgr) { bgr.B = bgra.B; bgr.G = bgra.G; bgr.R = bgra.R; } /// /// Converts 8-bit Bgra to 8-bit Gray. /// /// Source color. /// Destination color. public static void Convert(Bgra bgra, ref Gray gray) { Bgr bgr = default(Bgr); Convert(bgra, ref bgr); Bgr.Convert(bgr, ref gray); } } /// /// Represents 8-bit Bgra color type. /// Its usage should be restricted only for unsafe pixel manipulation. /// public struct Bgra8 { /// /// Gets or sets the blue component. /// public byte B; /// /// Gets or sets the green component. /// public byte G; /// /// Gets or sets the red component. /// public byte R; /// /// Gets or sets the alpha component. /// public byte A; } } ================================================ FILE: Source/Image/ColorTypeConversions/ColorSpaces/Gray.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Runtime.InteropServices; namespace DotImaging { /// /// Represents gray color of type color depth. /// [StructLayout(LayoutKind.Sequential)] public struct Gray : IColor where T: unmanaged { /// /// Creates new gray color. /// /// Intensity. public Gray(T intensity) { this.Intensity = intensity; } /// /// Gets or sets the intensity. /// public T Intensity; /// /// Converts gray structure to value. /// /// Gray color. /// Intensity. public static implicit operator T(Gray gray) { return gray.Intensity; } /// /// Converts intensity of type to Gray color. /// /// Intensity. /// Gray color. public static implicit operator Gray(T intensity) { return new Gray(intensity); } /// /// Gets the string color representation. /// /// String color representation. public override string ToString() { return string.Format("{0}", Intensity); } /// /// Converts 8-bit gray intensity to the 8-bit Bgr color. /// /// Source color. /// Destination color. public static void Convert(Gray gray, ref Bgr bgr) { bgr.B = gray.Intensity; bgr.G = gray.Intensity; bgr.R = gray.Intensity; } /// /// Converts 8-bit gray intensity to the 8-bit Bgra color. /// /// Source color. /// Destination color. public static void Convert(Gray gray, ref Bgra bgra) { bgra.B = gray.Intensity; bgra.G = gray.Intensity; bgra.R = gray.Intensity; bgra.A = System.Byte.MaxValue; } } } ================================================ FILE: Source/Image/ColorTypeConversions/ColorSpaces/Hsv.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace DotImaging { /// /// Represents Hsv color type of type color depth. /// [StructLayout(LayoutKind.Sequential)] public struct Hsv: IColor3 where T: unmanaged { /// /// Creates new Hsv color. /// /// Hue /// Saturation /// Value. public Hsv(T hue, T saturation, T value) { this.H = hue; this.S = saturation; this.V = value; } /// /// Gets or sets hue. /// public T H; /// /// Gets or sets saturation. /// public T S; /// /// Gets or sets value. /// public T V; /// /// Gets the string color representation. /// /// String color representation. public override string ToString() { return string.Format("H: {0}, S: {1}, V: {2}", H, S, V); } /// /// Gets the index of the hue component. /// public const int IdxH = 0; /// /// Gets the index of the saturation component. /// public const int IdxS = 1; /// /// Gets the index of the value component. /// public const int IdxV = 2; /// /// Converts 8-bit Hsv color to the 8-bit Bgr color. /// /// Source color. /// Destination color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Convert(Hsv hsv, ref Bgr bgr) { if (hsv.S == 0) { bgr.R = hsv.V; bgr.G = hsv.V; bgr.B = hsv.V; return; } int hue = hsv.H * 2; //move to [0-360 range] (only needed for byte!) int hQuadrant = hue / 60; // Hue quadrant 0 - 5 (60deg) int hOffset = hue % 60; // Hue position in quadrant int vs = hsv.V * hsv.S; byte p = (byte)(hsv.V - (vs / 255)); byte q = (byte)(hsv.V - (vs / 255 * hOffset) / 60); byte t = (byte)(hsv.V - (vs / 255 * (60 - hOffset)) / 60); switch (hQuadrant) { case 0: bgr.R = hsv.V; bgr.G = t; bgr.B = p; break; case 1: bgr.R = q; bgr.G = hsv.V; bgr.B = p; break; case 2: bgr.R = p; bgr.G = hsv.V; bgr.B = t; break; case 3: bgr.R = p; bgr.G = q; bgr.B = hsv.V; break; case 4: bgr.R = t; bgr.G = p; bgr.B = hsv.V; break; default: bgr.R = hsv.V; bgr.G = p; bgr.B = q; break; } } } /// /// Provides extension conversion methods for 8-bit Hsv type. /// public static class HsvColorConversionExtensions { /// /// Converts 8-bit Hsv color to 8-bit Bgr. /// /// 8-bit Hsv color. /// 8-bit Bgr [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Bgr ToBgr(this Hsv hsv) { Bgr bgr = default(Bgr); Hsv.Convert(hsv, ref bgr); return bgr; } } } ================================================ FILE: Source/Image/ColorTypeConversions/ColorSpaces/IColor.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion namespace DotImaging { /// /// Default interface for color types. /// public interface IColor { } /// /// Default generic interface for color types. /// /// public interface IColor : IColor where T : struct { } /// /// Interface for 2 channel color type. (Used for compile-time restrictions) /// public interface IColor2 : IColor { } /// /// Generic interface for 2 channel color type. (Used for compile-time restrictions) /// public interface IColor2 : IColor2, IColor where T : struct { } /// /// Interface for 3 channel color type. (Used for compile-time restrictions) /// public interface IColor3 : IColor { } /// /// Generic interface for 3 channel color type. (Used for compile-time restrictions) /// /// Channel type. public interface IColor3 : IColor3, IColor where T : struct { } /// /// Interface for 4 channel color type. (Used for compile-time restrictions) /// public interface IColor4 : IColor { } /// /// Generic interface for 4 channel color type. (Used for compile-time restrictions) /// /// Channel type. public interface IColor4 : IColor4, IColor where T : struct { } } ================================================ FILE: Source/Image/ColorTypeConversions/ColorSpaces/Rgb.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace DotImaging { /// /// Represents Rgb color type of type color depth. /// [StructLayout(LayoutKind.Sequential)] public struct Rgb : IColor3 where T : unmanaged { /// /// Creates new Rgb color. /// /// Red /// Green /// Blue public Rgb(T r, T g, T b) { this.R = r; this.G = g; this.B = b; } /// /// Gets or sets the red component. /// public T R; /// /// Gets or sets the green component. /// public T G; /// /// Gets or sets the blue component. /// public T B; /// /// Gets the string color representation. /// /// String color representation. public override string ToString() { return string.Format("R: {0}, G: {1}, B: {2}", R, G, B); } /// /// Gets the index of the red component. /// public const int IdxR = 0; /// /// Gets the index of the green component. /// public const int IdxG = 1; /// /// Gets the index of the blue component. /// public const int IdxB = 2; /// /// Converts 8-bit Rgb to 8-bit Bgr. /// /// Source color. /// Destination color. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Convert(Rgb rgb, ref Bgr bgr) { rgb.R = bgr.R; rgb.G = bgr.G; rgb.B = bgr.B; } } /// /// Represents 8-bit Rgb color type. /// Its usage should be restricted only for unsafe pixel manipulation. /// public struct Rgb8 { /// /// Gets or sets the red component. /// public byte R; /// /// Gets or sets the green component. /// public byte G; /// /// Gets or sets the blue component. /// public byte B; } } ================================================ FILE: Source/Image/ColorTypeConversions/Converters/ColorConversionExtensions.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Drawing; using System; namespace DotImaging { /// /// Provides color conversion extension methods. /// public static class ColorConversionExtensions { #region Gray color conversion /// /// Converts the source color to the destination color. /// /// Source image. /// image with converted color. public static Bgr[,] ToBgr(this Gray[,] grayIm) { return grayIm.Convert, Bgr>(Gray.Convert); } /// /// Converts the source color to the destination color. /// /// Source image. /// Working area. /// image with converted color. public static Bgr[,] ToBgr(this Gray[,] grayIm, Rectangle area) { return grayIm.Convert, Bgr>(Gray.Convert, area); } /// /// Converts the source color to the destination color. /// /// Source image. /// image with converted color. public static Bgra[,] ToBgra(this Gray[,] grayIm) { return grayIm.Convert, Bgra>(Gray.Convert); } /// /// Converts the source color to the destination color. /// /// Source image. /// Working area. /// image with converted color. public static Bgra[,] ToBgra(this Gray[,] grayIm, Rectangle area) { return grayIm.Convert, Bgra>(Gray.Convert, area); } #endregion #region Bgr color conversion /// /// Converts the source color to the destination color. /// /// Source image. /// image with converted color. public static Bgra[,] ToBgra(this Bgr[,] image) { return image.Convert, Bgra>(Bgr.Convert); } /// /// Converts the source color to the destination color. /// /// Source image. /// Working area. /// image with converted color. public static Bgra[,] ToBgra(this Bgr[,] image, Rectangle area) { return image.Convert, Bgra>(Bgr.Convert, area); } /// /// Converts the source color to the destination color. /// /// Source image. /// image with converted color. public static Gray[,] ToGray(this Bgr[,] image) { return image.Convert, Gray>(Bgr.Convert); } /// /// Converts the source color to the destination color. /// /// Source image. /// Working area. /// image with converted color. public static Gray[,] ToGray(this Bgr[,] image, Rectangle area) { return image.Convert, Gray>(Bgr.Convert, area); } /// /// Converts the source color to the destination color. /// /// Source image. /// image with converted color. public static Hsv[,] ToHsv(this Bgr[,] image) { return image.Convert, Hsv>(Bgr.Convert); } /// /// Converts the source color to the destination color. /// /// Source image. /// Working area. /// image with converted color. public static Hsv[,] ToHsv(this Bgr[,] image, Rectangle area) { return image.Convert, Hsv>(Bgr.Convert, area); } #endregion #region Rgb color conversion /// /// Converts the source color to the destination color. /// /// Source image. /// image with converted color. public static Bgr[,] ToBgr(this Rgb[,] image) { return image.Convert, Bgr>(Rgb.Convert); } /// /// Converts the source color to the destination color. /// /// Source image. /// Working area. /// image with converted color. public static Bgr[,] ToBgr(this Rgb[,] image, Rectangle area) { return image.Convert, Bgr>(Rgb.Convert, area); } #endregion #region Bgra color conversion /// /// Converts the source color to the destination color. /// /// Source image. /// Image with converted color. public static Bgr[,] ToBgr(this Bgra[,] image) { return image.Convert, Bgr>(Bgra.Convert); } /// /// Converts the source color to the destination color. /// /// Source image. /// Working area. /// Image with converted color. public static Bgr[,] ToBgr(this Bgra[,] image, Rectangle area) { return image.Convert, Bgr>(Bgra.Convert, area); } /// /// Converts the source color to the destination color. /// /// Source image. /// Image with converted color. public static Gray[,] ToGray(this Bgra[,] image) { return image.Convert, Gray>(Bgra.Convert); } /// /// Converts the source color to the destination color. /// /// Source image. /// Working area. /// Image with converted color. public static Gray[,] ToGray(this Bgra[,] image, Rectangle area) { return image.Convert, Gray>(Bgra.Convert, area); } #endregion #region Hsv color conversion /// /// Converts the source color to the destination color. /// /// Source image. /// image with converted color. public static Bgr[,] ToBgr(this Hsv[,] image) { return image.Convert, Bgr>(Hsv.Convert); } /// /// Converts the source color to the destination color. /// /// Source image. /// Working area. /// image with converted color. public static Bgr[,] ToGray(this Hsv[,] image, Rectangle area) { return image.Convert, Bgr>(Hsv.Convert, area); } #endregion #region Unmanaged image and array cloning (ToBgr(), ToBgra(), ToGray()) /// /// Converts the specified image into Bgr managed image. /// /// Bgr, Bgra or Gray type image. /// Bgr image or null if conversion can not be performed. public static Bgr[,] ToBgr(this IImage image) { if (image is Image>) { return (image as Image>).Clone().ToBgr(); } else if (image is Image>) { return (image as Image>).Clone(); } else if (image is Image>) { return (image as Image>).Clone().ToBgr(); } else { return null; } } /// /// Converts the specified image into Bgra managed image. /// /// Bgr, Bgra or Gray type image. /// Bgra image or null if conversion can not be performed. public static Bgra[,] ToBgra(this IImage image) { if (image is Image>) { return (image as Image>).Clone(); } else if (image is Image>) { return (image as Image>).Clone().ToBgra(); } else if (image is Image>) { return (image as Image>).Clone().ToBgra(); } else { return null; } } /// /// Converts the specified image into gray managed image. /// /// Bgr, Bgra or Gray type image. /// Gray image or null if conversion can not be performed. public static Gray[,] ToGray(this IImage image) { if (image is Image>) { return (image as Image>).ToGray(); } else if (image is Image>) { return (image as Image>).Clone().ToGray(); } else if (image is Image>) { return (image as Image>).Clone(); } else { return null; } } /// /// Converts the specified 2D array into Bgr managed image. /// If the specified array is the Bgr managed image, the source is returned. /// /// Bgr, Bgra or Gray type bitmap. /// Bgr image or null if conversion can not be performed. public static Bgr[,] ToBgr(this Array array2D) { if (array2D is Bgra[,]) { return ((Bgra[,])array2D).ToBgr(); } else if (array2D is Bgr[,]) { return ((Bgr[,])array2D); } else if (array2D is Gray[,]) { return ((Gray[,])array2D).ToBgr(); } else { return null; } } /// /// Converts the specified 2D array into Bgra managed image. /// If the specified array is the Bgra managed image, the source is returned. /// /// Bgra, Bgr or Gray type bitmap. /// Bgra image or null if conversion can not be performed. public static Bgra[,] ToBgra(this Array array2D) { if (array2D is Bgra[,]) { return (Bgra[,])array2D; } else if (array2D is Bgr[,]) { return ((Bgr[,])array2D).ToBgra(); } else if (array2D is Gray[,]) { return ((Gray[,])array2D).ToBgra(); } else { return null; } } /// /// Converts the specified 2D array into gray managed image. /// If the specified array is the gray managed image, the source is returned. /// /// Bgra, Bgr or Gray type bitmap. /// Gray image or null if conversion can not be performed. public static Gray[,] ToGray(this Array array2D) { if (array2D is Bgra[,]) { return ((Bgra[,])array2D).ToGray(); } else if (array2D is Bgr[,]) { return ((Bgr[,])array2D).ToGray(); } else if (array2D is Gray[,]) { return (Gray[,])array2D; } else { return null; } } #endregion } } ================================================ FILE: Source/Image/Extensions/BasicExtensions.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Drawing; using System; namespace DotImaging { /// /// Provides basic image extensions for a two-dimensional array. /// public static class ArrayImageBasicExtensions { /// /// Gets image width. /// /// Element type. /// Image. /// The image width. public static int Width(this T[,] image) { return image.GetLength(1); } /// /// Gets image height. /// /// Element type. /// Image. /// The image height. public static int Height(this T[,] image) { return image.GetLength(0); } /// /// Gets image size. /// /// Element type. /// Image. /// The image size. public static Size Size(this T[,] image) { return new Size(image.Width(), image.Height()); } /// /// Pins the array and returns the corresponding generic image. /// /// Color type. /// The array to lock. /// The generic image which shares data with the pined array. public static Image Lock(this TColor[,] array) where TColor: unmanaged { return Image.Lock(array); } /// /// Pins the array and returns the corresponding generic image of a specified portion. /// /// Color type. /// The array to lock. /// Working area. /// The generic image which shares data with the pined array. public static Image Lock(this TColor[,] array, Rectangle area) where TColor: unmanaged { return Image.Lock(array).GetSubRect(area); } /// /// Sets all elements of the array to the default value. /// /// Element type. /// Array to clear. public static void Clear(this T[,] array) where T: unmanaged { Array.Clear(array, 0, array.Length); } /// /// Performs deep cloning of the specified array. /// /// Element type. /// Array. /// Cloned array. public static T[,] Clone(this T[,] array) where T: unmanaged { return (T[,])array.Clone(); } /// /// Creates new array of the same size as the source array. /// /// Element type. /// Array. /// New empty array. public static T[,] CopyBlank(this T[,] array) { return new T[array.Height(), array.Width()]; } /// /// Gets the element info of the specified array. /// /// Element type. /// Array. /// Array element info. public static ColorInfo ColorInfo(this TColor[,] source) where TColor: unmanaged { return DotImaging.ColorInfo.GetInfo(); } /// /// Calculates image stride for the specified alignment. /// /// Image. /// Data alignment. /// Image stride. public static int CalculateStride(this TImage image, int allignment = 4) where TImage: IImage { int stride = image.Width * image.ColorInfo.Size; if (allignment != 0 && stride % allignment != 0) { stride += (allignment - (stride % allignment)); } return stride; } /// /// Applies the specified conversion function to each source pixel, producing the destination image. /// /// Source element type. /// Destination element type. /// Source array. /// Pixel conversion function. /// Destination array. public static TDst[,] Convert(this TSrc[,] source, Func convert) { Size imSize = source.Size(); TDst[,] dest = new TDst[imSize.Height, imSize.Width]; ParallelLauncher.Launch(thread => { dest[thread.Y, thread.X] = convert(source[thread.Y, thread.X]); }, source.Width(), source.Height()); return dest; } /// /// Applies the specified conversion function to each source pixel, producing the destination image. /// /// Element type. /// Source array. /// Pixel conversion function. /// /// True to apply the function in place, false otherwise. /// If true the result image is the same as source image. /// /// Destination array. public static T[,] Apply(this T[,] source, Func apply, bool inPlace = false) { Size imSize = source.Size(); T[,] dest = inPlace ? source : new T[imSize.Height, imSize.Width]; ParallelLauncher.Launch(thread => { dest[thread.Y, thread.X] = apply(source[thread.Y, thread.X]); }, source.Width(), source.Height()); return dest; } #region Set value /// /// Sets the specified value for each element of the array. /// /// Element type. /// Array with value type elements. /// Value to set. public static void SetValue(this T[,] array, T value) where T : struct { ParallelLauncher.Launch((thread) => { array[thread.Y, thread.X] = value; }, array.Width(), array.Height()); } /// /// Sets the specified value for each element of the array. /// /// Element type. /// Array with value type elements. /// Value to set. /// Working area. public static void SetValue(this T[,] array, T value, Rectangle area) where T : struct { ParallelLauncher.Launch((thread) => { array[thread.Y + area.Y, thread.X + area.X] = value; }, area.Width, area.Height); } /// /// Sets the specified value for only those element of the array where the mask is true. /// /// Element type. /// Array with value type elements. /// Value to set. /// Working area. /// Mask. public static void SetValue(this T[,] array, T value, Rectangle area, bool[,] mask) { if (array.Size() != mask.Size()) throw new ArgumentException("Array and mask must have the same size."); ParallelLauncher.Launch((thread) => { if (mask[thread.Y + area.Y, thread.X + area.X]) array[thread.Y + area.Y, thread.X + area.X] = value; }, area.Width, area.Height); } /// /// Sets the specified value for only those element of the array where the mask is non-zero. /// /// Element type. /// Array with value type elements. /// Value to set. /// Working area. /// Mask. public static void SetValue(this T[,] array, T value, Rectangle area, Gray[,] mask) { if (array.Size() != mask.Size()) throw new ArgumentException("Array and mask must have the same size."); ParallelLauncher.Launch((thread) => { if (mask[thread.Y + area.Y, thread.X + area.X] != 0) array[thread.Y + area.Y, thread.X + area.X] = value; }, area.Width, area.Height); } /// /// Sets the specified value for only those element of the array where the mask is non-zero. /// /// Element type. /// Array with value type elements. /// Value to set. /// Mask. public static void SetValue(this T[,] array, T value, Gray[,] mask) { if (array.Size() != mask.Size()) throw new ArgumentException("Array and mask must have the same size."); ParallelLauncher.Launch((thread) => { if (mask[thread.Y, thread.X] != 0) array[thread.Y, thread.X] = value; }, array.Width(), array.Height()); } /// /// Sets the specified value for only those element of the array where the mask is true. /// /// Element type. /// Array with value type elements. /// Value to set. /// Mask. public static void SetValue(this T[,] array, T value, bool[,] mask) { if (array.Size() != mask.Size()) throw new ArgumentException("Array and mask must have the same size."); ParallelLauncher.Launch((thread) => { if (mask[thread.Y, thread.X]) array[thread.Y, thread.X] = value; }, array.Width(), array.Height()); } #endregion } } ================================================ FILE: Source/Image/Extensions/ChannelMerger.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Collections.Generic; using System.Drawing; namespace DotImaging { /// /// Provides channel merge extensions. /// public static class ChannelMerger { /// /// Combines provided channels into single image with interleaved channels. /// /// Source color type. /// Channel depth type. /// Channel collection. /// Channel indicies. If null, all channels are taken. /// Image. public static TSrcColor[,] MergeChannels(this IList[,]> channels, params int[] channelIndices) where TSrcColor : unmanaged, IColor where TDepth : unmanaged { var area = new Rectangle(new Point(), channels[0].Size()); return channels.MergeChannels(area, channelIndices); } /// /// Combines provided channels into single image with interleaved channels. /// /// Source color type. /// Channel depth type. /// Channel collection. /// Working area. /// Channel indicies. If null, all channels are taken. /// Image. public static TSrcColor[,] MergeChannels(this IList[,]> channels, Rectangle area, params int[] channelIndices) where TSrcColor : unmanaged, IColor where TDepth : unmanaged { TSrcColor[,] image = new TSrcColor[area.Height, area.Width]; using (var im = image.Lock()) { for (int i = 0; i < channelIndices.Length; i++) { using (var ch = channels[i].Lock()) { replaceChannel(im, ch.GetSubRect(area), channelIndices[i]); } } } return image; } /// /// Replaces the selected image channel with the specified channel. /// /// Source color type. /// Channel depth type. /// Image. /// Channel. /// Index of a channel to replace. public static void ReplaceChannel(this TSrcColor[,] image, Gray[,] channel, int channelIndex) where TSrcColor : unmanaged, IColor where TDepth : unmanaged { using (var im = image.Lock()) using (var ch = channel.Lock()) { replaceChannel(im, ch, channelIndex); } } private static unsafe void replaceChannel(Image image, Image> channel, int channelIndex) where TSrcColor : unmanaged, IColor where TDepth : unmanaged { int width = image.Width; int height = image.Height; int channelSize = image.ColorInfo.ChannelSize; int colorSize = image.ColorInfo.Size; byte* srcPtr = (byte*)channel.ImageData; byte* dstPtr = (byte*)image.ImageData + channelIndex * image.ColorInfo.ChannelSize;; for (int row = 0; row < height; row++) { byte* srcColPtr = srcPtr; byte* dstColPtr = dstPtr; for (int col = 0; col < width; col++) { /********** copy channel byte-per-byte ************/ for (int partIdx = 0; partIdx < channelSize; partIdx++) { dstPtr[partIdx] = srcColPtr[partIdx]; } srcColPtr += channelSize; //move to the next column dstColPtr += colorSize; /********** copy channel byte-per-byte ************/ } srcPtr += channel.Stride; dstPtr += image.Stride; } } } } ================================================ FILE: Source/Image/Extensions/ChannelSplitter.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Linq; using System.Drawing; namespace DotImaging { /// /// Provides channel splitting extensions. /// public static class ChannelSplitter { /// /// Extracts the specified image channels. /// /// Source color type. /// Channel depth type. /// Image. /// Channel indicies to extract. If null, all channels are extracted. /// Channel collection. public static unsafe Gray[][,] SplitChannels(this TSrcColor[,] image, params int[] channelIndices) where TSrcColor : unmanaged, IColor where TDepth : unmanaged { Rectangle area = new Rectangle(0, 0, image.Width(), image.Height()); return image.SplitChannels(area, channelIndices); } /// /// Extracts the specified image channels. /// /// Source color type. /// Channel depth type. /// Image. /// Working area. /// Channel indicies to extract. If null, all channels are extracted. /// Channel collection. public static unsafe Gray[][,] SplitChannels(this TSrcColor[,] image, Rectangle area, params int[] channelIndices) where TSrcColor: unmanaged, IColor where TDepth: unmanaged { if (channelIndices == null || channelIndices.Length == 0) { channelIndices = Enumerable.Range(0, ColorInfo.GetInfo().ChannelCount).ToArray(); } var channels = new Gray[channelIndices.Length][,]; for (int i = 0; i < channelIndices.Length; i++) { channels[i] = GetChannel(image, area, channelIndices[i]); } return channels; } /// /// Extracts a single image channel. /// /// Source color type. /// Channel depth type. /// Image. /// Channel index. /// Extracted channel. public static unsafe Gray[,] GetChannel(this TSrcColor[,] image, int channelIndex) where TSrcColor : unmanaged, IColor where TDepth : unmanaged { Rectangle area = new Rectangle(0, 0, image.Width(), image.Height()); return image.GetChannel(area, channelIndex); } /// /// Extracts a single image channel. /// /// Source color type. /// Channel depth type. /// Image. /// Working area. /// Channel index. /// Extracted channel. public static unsafe Gray[,] GetChannel(this TSrcColor[,] image, Rectangle area, int channelIndex) where TSrcColor: unmanaged, IColor where TDepth: unmanaged { int width = area.Width; int height = area.Height; var dest = new Gray[area.Height, area.Width]; using (var lockedImage = image.Lock()) using (var dstImg = dest.Lock()) { var srcImg = lockedImage.GetSubRect(area); int channelSize = srcImg.ColorInfo.ChannelSize; int colorSize = srcImg.ColorInfo.Size; byte* srcPtr = (byte*)srcImg.ImageData + channelIndex * srcImg.ColorInfo.ChannelSize; byte* dstPtr = (byte*)dstImg.ImageData; for (int row = 0; row < height; row++) { byte* srcColPtr = srcPtr; byte* dstColPtr = dstPtr; for (int col = 0; col < width; col++) { /********** copy channel byte-per-byte ************/ for (int partIdx = 0; partIdx < channelSize; partIdx++) { dstColPtr[partIdx] = srcColPtr[partIdx]; } srcColPtr += colorSize; //move to the next column dstColPtr += channelSize; /********** copy channel byte-per-byte ************/ } srcPtr += srcImg.Stride; dstPtr += dstImg.Stride; } } return dest; } } } ================================================ FILE: Source/Image/Extensions/Convert.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Drawing; namespace DotImaging { /// /// Element conversion delegate. /// /// Source element type. /// Destination element type. /// Source element. /// Destination element. public delegate void Convert(TSrc source, ref TDst destination) where TSrc : unmanaged where TDst : unmanaged; /// /// Provides generic element conversion extensions. /// public static class ConvertExtensions { /// /// Converts each element of the array by using the specified conversion function. /// /// Source element type. /// Destination element type. /// Source array. /// Conversion function. /// Destination array. public static TDst[,] Convert(this TSrc[,] source, Convert convert) where TSrc : unmanaged where TDst : unmanaged { var area = new Rectangle(0, 0, source.GetLength(1), source.GetLength(0)); return source.Convert(convert, area); } /// /// Converts each element of the array by using the specified conversion function. /// /// Source element type. /// Destination element type. /// Source array. /// Conversion function. /// Working area. public static TDst[,] Convert(this TSrc[,] source, Convert convert, Rectangle area) where TSrc : unmanaged where TDst : unmanaged { TDst[,] destination = new TDst[area.Height, area.Width]; var offset = area.Location; ParallelLauncher.Launch(thread => { convert(source[thread.Y + offset.Y, thread.X + offset.X], ref destination[thread.Y, thread.X]); }, area.Width, area.Height); return destination; } } } ================================================ FILE: Source/Image/Extensions/Copy.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Drawing; using System.Runtime.InteropServices; namespace DotImaging { /// /// Provides methods for unsafe data copying as well as extensions for generic image and array cloning. /// public static class Copy { [DllImport("ntdll.dll", CallingConvention = CallingConvention.Cdecl)] private static unsafe extern IntPtr memcpy(IntPtr dst, IntPtr src, int count); static Copy() { if (Environment.OSVersion.Platform == PlatformID.Win32NT) Copy.UnsafeCopy = (src, dst, count) => memcpy(dst, src, count); else Copy.UnsafeCopy = unsafeCopy_ElementByElement; } /// /// Copy block of unmanaged memory. /// /// /// Source pointer. /// Destination pointer. /// Memory block's length to copy. /// /// This function is required because of the fact that .NET does /// not provide any way to copy unmanaged blocks, but provides only methods to /// copy from unmanaged memory to managed memory and vise versa. public delegate void UnsafeCopyFunc(IntPtr src, IntPtr dst, int count); /// /// Copy block of unmanaged memory. /// public static readonly UnsafeCopyFunc UnsafeCopy; /// /// Copy block of unmanaged memory. /// /// /// Source pointer. /// Destination pointer. /// Memory block's length to copy. /// /// This function is required because of the fact that .NET does /// not provide any way to copy unmanaged blocks, but provides only methods to /// copy from unmanaged memory to managed memory and vise versa. static unsafe void unsafeCopy_ElementByElement(IntPtr src, IntPtr dst, int count) //Taken from AForge.NET and modified. { int countUint = count >> 2; int countByte = count & 3; uint* dstUint = (uint*)dst; uint* srcUint = (uint*)src; while (countUint-- != 0) { *dstUint++ = *srcUint++; } byte* dstByte = (byte*)dstUint; byte* srcByte = (byte*)srcUint; while (countByte-- != 0) { *dstByte++ = *srcByte++; } } /// /// Copies unmanaged data from the specified source to the specified destination patch. /// /// Source pointer. /// Destination pointer. /// Source stride. /// Destination stride. /// Amount of bytes per row to be copied (width for byte fields). (common: image width * color size) /// Field's height. public unsafe static void UnsafeCopy2D(IntPtr srcPtr, IntPtr destPtr, int srcStride, int destStride, int patchStride, int patchHeight) { if (srcStride == destStride && srcStride == patchStride) UnsafeCopy(srcPtr, destPtr, srcStride * patchHeight); else { byte* srcImgPtr = (byte*)srcPtr; byte* destImgPtr = (byte*)destPtr; for (int i = 0; i < patchHeight; i++) { UnsafeCopy((IntPtr)srcImgPtr, (IntPtr)destImgPtr, patchStride); srcImgPtr += srcStride; destImgPtr += destStride; } } } /// /// Copies unmanaged data from the specified source to the specified destination. /// /// Source pointer. /// Destination pointer. /// Source stride. /// Destination stride. /// Field's height. public unsafe static void UnsafeCopy2D(IntPtr srcPtr, IntPtr destPtr, int srcStride, int destStride, int destHeight) { UnsafeCopy2D(srcPtr, destPtr, srcStride, destStride, destStride, destHeight); } /// /// Clones the portion of the provided array. /// /// Element type. /// Array. /// Working area. /// Cloned portion of the array. public static T[,] Clone(this T[,] array, Rectangle area) where T : unmanaged { //error handling in Lock(...) var destination = new T[area.Height, area.Width]; using(var srcImg = array.Lock(area)) using (var dstImg = destination.Lock()) { UnsafeCopy2D(srcImg.ImageData, dstImg.ImageData, srcImg.Stride, dstImg.Stride, dstImg.Height); } return destination; } /// /// Clones the provided image. /// /// Element type. /// Image. /// Cloned image. public static T[,] Clone(this Image image) where T : unmanaged { if (image == null) return null; //error handling in CopyTo(..) var destination = new T[image.Height, image.Width]; CopyTo(image, destination); return destination; } /// /// Copies the specified source image to the destination image. /// Source and destination image must have the same size. /// /// Element type. /// Source image. /// Destination image. public static void CopyTo(this Image source, Image destination) where T : unmanaged { if (source.Size != destination.Size) throw new ArgumentException("Source dimension must be the same as destination dimension."); UnsafeCopy2D(source.ImageData, destination.ImageData, source.Stride, destination.Stride, destination.Height); } /// /// Copies the specified source image to the destination image. /// Source and destination image must have the same size. /// /// Element type. /// Source image. /// Destination image. public static void CopyTo(this Image source, T[,] destination) where T: unmanaged { //error handling in CopyTo(..) using (var dstImg = destination.Lock()) { CopyTo(source, dstImg); } } /// /// Copies the specified source image to the destination image. /// Source and destination image must have the same size. /// /// Element type. /// Source image. /// Destination image. /// Destination location. public static void CopyTo(this T[,] source, T[,] destination, Point destinationOffset = default) where T: unmanaged { var destRect = new Rectangle(destinationOffset, source.Size()); using (var srcImg = source.Lock()) using (var dstImg = destination.Lock(destRect)) { UnsafeCopy2D(srcImg.ImageData, dstImg.ImageData, srcImg.Stride, dstImg.Stride, dstImg.Height); } } /// /// Copies the image source to the destination buffer. /// If the buffer does not have the same size as the source image, or the buffer is null, the destination buffer will be recreated. /// /// Color type. /// Source image. /// destination buffer. public static void CopyToOrCreate(this Image source, ref TColor[,] destinationBuffer) where TColor: unmanaged { if (source == null) { destinationBuffer = null; return; } if (destinationBuffer == null || source.Width != destinationBuffer.Width() || source.Height != destinationBuffer.Height()) { destinationBuffer = source.Clone(); } else { source.CopyTo(destinationBuffer); } } /// /// Copies values from source to destination image using mask. Destination values where mask == 0 are not erased!. /// /// Element type. /// Image. /// Destination image /// Mask. Color locations that need to be copied must be set to !=0 in mask. public static void CopyTo(this TColor[,] source, TColor[,] destination, Gray[,] mask) where TColor: unmanaged { if (source.Size() != mask.Size() || source.Size() != destination.Size()) throw new Exception("Image, mask, destination image must have the same size."); ParallelLauncher.Launch((thread) => { if (mask[thread.Y, thread.X] != 0) destination[thread.Y, thread.X] = source[thread.Y, thread.X]; }, source.Width(), source.Height()); } /// /// Copies only those values from source to destination image area at which destination mask is true. /// /// Element type. /// Source. /// Source area. /// Destination. /// Destination location. /// Destination mask. public static void CopySelective(this T[,] source, Rectangle sourceArea, T[,] destination, Point destinationOffset, bool[,] destinationMask) { if(source.Size() != destinationMask.Size() || source.Size() != destination.Size()) throw new Exception("Image, mask, destination image must have the same size."); ParallelLauncher.Launch((thread) => { if (destinationMask[destinationOffset.Y + thread.Y, destinationOffset.X + thread.X]) destination[destinationOffset.Y + thread.Y, destinationOffset.X + thread.X] = source[sourceArea.Y + thread.Y, sourceArea.X + thread.X]; }, sourceArea.Width, sourceArea.Height); } } } ================================================ FILE: Source/Image/Extensions/ImageFlipping.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Drawing; namespace DotImaging { /// /// Flip image direction. /// They can be used as bit flags. /// [Flags] public enum FlipDirection { /// /// No flipping. /// None = 0x0, /// /// Horizontal flipping. /// Horizontal = 0x1, /// /// Vertical flipping /// Vertical = 0x2, /// /// All flipping (horizontal + vertical). /// All = 0x3 } /// /// Contains extension methods for image flipping. /// public static class ImageFlipping { /// /// Flips an input image horizontally / vertically / both directions / or none (data copy). /// /// Color type. /// Input image. /// Flip direction. /// Returns flipped image. public static TColor[,] FlipImage(this TColor[,] source, FlipDirection flipDirection) where TColor: unmanaged { TColor[,] dest = source.CopyBlank(); var sourceArea = new Rectangle(0, 0, source.Width(), source.Height()); var destinationOffset = new Point(); source.FlipImage(sourceArea, dest, destinationOffset, flipDirection); return dest; } /// /// Flips an input image horizontally / vertically / both directions / or none (data copy). /// /// Color type. /// Input image. /// Source area. /// Destination image. /// Destination image offset. /// Flip direction. public static void FlipImage(this TColor[,] source, Rectangle sourceArea, TColor[,] destination, Point destinationOffset, FlipDirection flipDirection) { int startDstRow = 0; int vDirection = 1; int startDstCol = 0; int hDirection = 1; if ((flipDirection & FlipDirection.Vertical) != 0) { startDstRow = (destinationOffset.Y + sourceArea.Height) - 1; vDirection = -1; } if ((flipDirection & FlipDirection.Horizontal) != 0) { startDstCol = (destinationOffset.X + sourceArea.Width) - 1; hDirection = -1; } for (int srcRow = 0, dstRow = startDstRow; srcRow < sourceArea.Bottom; srcRow++, dstRow += vDirection) { for (int srcCol = 0, dstCol = startDstCol; srcCol < sourceArea.Right; srcCol++, dstCol += hDirection) { destination[dstRow, dstCol] = source[srcRow, srcCol]; } } } } } ================================================ FILE: Source/Image/Extensions/SpatialConvolution.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Drawing; namespace DotImaging { /// /// Provides extension methods for the image spatial convolution. /// public static class SpatialConvolution { /*private unsafe static void convolve(KernelThread thread, float[,] source, float[,] kernel, float[,] destination) { int kernelWidth = kernel.Width(); int kernelHeight = kernel.Height(); var sum = 0f; for (int r = 0; r < kernelHeight; r++) { for (int c = 0; c < kernelWidth; c++) { sum += source[thread.Y + r, thread.X + c] * kernel[r, c]; } } destination[thread.Y + kernelHeight / 2, thread.X + kernelWidth / 2] = sum; }*/ private unsafe static void convolve(KernelThread thread, float* source, int sourceStride, int channelCount, float* kernel, int kernelWidth, int kernelHeight, float* destination, int destinationStride) { source = (float*)((byte*)source + sourceStride * thread.Y) + thread.X; destination = (float*)((byte*)destination + destinationStride * (thread.Y + kernelHeight / 2)) + (thread.X + kernelWidth / 2); for (int ch = 0; ch < channelCount; ch++) { var srcPtr = source + ch; var krnlPtr = kernel; var sum = 0f; for (int r = 0; r < kernelHeight; r++) { for (int c = 0, srcCol = 0; c < kernelWidth; c++, srcCol += channelCount) { sum += srcPtr[srcCol] * krnlPtr[c]; } srcPtr = (float*)((byte*)srcPtr + sourceStride); krnlPtr += kernelWidth; } destination[ch] = sum; } } /// /// Convolves the source image with the specified kernel. /// /// Source data pointer. /// Source width. /// Source height. /// Source stride. /// Source channel count. /// Kernel pointer. /// Kernel width. /// Kernel height. /// Destination pointer. /// Destination stride. public unsafe static void ConvolveUnsafe(float* source, int sourceWidth, int sourceHeight, int sourceStride, int channelCount, float* kernel, int kernelWidth, int kernelHeight, float* destination, int destinationStride) { ParallelLauncher.Launch(thread => { convolve(thread, source, sourceStride, channelCount, kernel, kernelWidth, kernelHeight, destination, destinationStride); }, sourceWidth - kernelWidth, sourceHeight - kernelHeight); } /// /// Convolves the source image with the specified kernel. /// /// Source image. /// Kernel. /// Working area. /// Convolved image. public unsafe static float[,] Convolve(this float[,] source, float[,] kernel, Rectangle area) { var destination = new float[area.Height, area.Width]; fixed (float* srcPtr = &source[area.Y, area.X], kernelPtr = kernel, dstPtr = destination) { ConvolveUnsafe(srcPtr, area.Width, area.Height, source.Width() * sizeof(float), 1, kernelPtr, kernel.Width(), kernel.Height(), dstPtr, destination.Width() * sizeof(float)); } return destination; } /// /// Convolves the source image with the specified kernel. /// /// Source image. /// Kernel. /// Convolved image. public unsafe static float[,] Convolve(this float[,] source, float[,] kernel) { var area = new Rectangle(0, 0, source.Width(), source.Height()); return source.Convolve(kernel, area); } /// /// Convolves the source image with the specified kernel. /// /// Color type. /// Source image. /// Kernel. /// Convolved image. public unsafe static TColor[,] Convolve(this TColor[,] source, float[,] kernel) where TColor: unmanaged, IColor { var channelCount = source.ColorInfo().ChannelCount; var destination = source.CopyBlank(); using (var srcImg = source.Lock()) using(var dstImg = destination.Lock()) { fixed(float* kernelPtr = kernel) { ConvolveUnsafe((float*)srcImg.ImageData, srcImg.Width, srcImg.Height, srcImg.Stride, channelCount, kernelPtr, kernel.Width(), kernel.Height(), (float*)dstImg.ImageData, dstImg.Stride); } } return destination; } } } ================================================ FILE: Source/Image/Image.csproj ================================================  DotImaging.Image DotImaging true AnyCPU bin\DotImaging.Image.xml true 5.3.0 DotImaging.Image .NET image array extensions. Color and depth conversions. Slim unmanaged structure for fast pixel manipulation. LINQ on 2D arrays. image, managed-image, array-image, 2D LINQ Darko Jurić Darko Jurić https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Licence.txt https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Logo/logo-small.png https://raw.githubusercontent.com/dajuric/dot-imaging/ https://raw.githubusercontent.com/dajuric/dot-imaging/ true ../../Deploy/NuGet/bin/ Readme.txt ================================================ FILE: Source/Image/Interop/CvMat.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Collections.Generic; using System.Runtime.InteropServices; namespace DotImaging { /// /// OpenCV's Mat structure /// [StructLayout(LayoutKind.Sequential)] public unsafe struct CvMat { /// /// OpenCV's channel depth enumeration. /// public enum CvChannelDepth : int { /// /// 8-bit unsigned type. /// CV_8U = 0, /// /// 8-bit signed type. /// CV_8S = 1, /// /// 16-bit unsigned type. /// CV_16U = 2, /// /// 16-bit signed type. /// CV_16S = 3, /// /// 32-bit integer signed type. /// CV_32S = 4, /// /// 32-bit floating-point signed type. /// CV_32F = 5, /// /// 64-bit floating-point signed type. /// CV_64F = 6, /// /// User defined type. /// UserType = 7 } const int CV_CN_SHIFT = 3; /// /// Encoded mat depth and number of channels. /// int matType; /// /// Number of bytes per image row. /// public int Step; //internal int* refCount; int hdr_refcount; /// /// Image data pointer. /// public IntPtr ImageData; /// /// Image height. /// public int Height; /// /// Image width. /// public int Width; /// /// Creates new CvMat from the already existing data. /// /// Image data pointer. /// Image width. /// Image height. /// Number of bytes per row. /// Channel depth. /// Channel count. /// public static CvMat FromUserData(IntPtr imageData, int width, int height, int stride, CvChannelDepth depthType, int channelCount) { //taken from: https://github.com/Itseez/opencv/blob/ddf82d0b154873510802ef75c53e628cd7b2cb13/modules/core/include/opencv2/core/types_c.h const int CV_MAT_MAGIC_VAL = 0x42420000; //CV_MAKETYPE from: https://github.com/Itseez/opencv/blob/ddf82d0b154873510802ef75c53e628cd7b2cb13/modules/core/include/opencv2/core/cvdef.h const int CV_MAT_CONT_FLAG_SHIFT = 14; const int CV_MAT_CONT_FLAG = (1 << CV_MAT_CONT_FLAG_SHIFT); //CV_MAKETYPE from: https://github.com/Itseez/opencv/blob/ddf82d0b154873510802ef75c53e628cd7b2cb13/modules/core/include/opencv2/core/cvdef.h var matDepth = getDepth((int)depthType); var cvType = matDepth + ((channelCount - 1) << CV_CN_SHIFT); var mType = CV_MAT_MAGIC_VAL | CV_MAT_CONT_FLAG | cvType; return new CvMat { ImageData = imageData, Width = width, Height = height, Step = stride, matType = mType, hdr_refcount = 0, refCount = null }; } /// /// Gets the channel depth. /// public CvChannelDepth ChannelDepth { get { return (CvChannelDepth)getDepth(matType); } } /// /// Gets the channel count. /// public int ChannelCount { get { //CV_ELEM_SIZE from: https://github.com/Itseez/opencv/blob/ddf82d0b154873510802ef75c53e628cd7b2cb13/modules/core/include/opencv2/core/cvdef.h //0x3a50 = 11 10 10 01 01 00 00 ~ array of log2(sizeof(arr_type_elem)) const int CV_CN_MAX = 512; const int CV_MAT_CN_MASK = ((CV_CN_MAX - 1) << CV_CN_SHIFT); var CV_MAT_CN = (((matType & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1); return (CV_MAT_CN << ((((sizeof(int) / 4 + 1) * 16384 | 0x3a50) >> getDepth(matType) * 2) & 3)); } } //CV_MATDEPTH from: https://github.com/Itseez/opencv/blob/ddf82d0b154873510802ef75c53e628cd7b2cb13/modules/core/include/opencv2/core/cvdef.h static int getDepth(int flags) { const int CV_DEPTH_MAX = (1 << CV_CN_SHIFT); const int CV_MAT_DEPTH_MASK = (CV_DEPTH_MAX - 1); return (flags & CV_MAT_DEPTH_MASK); } } /// /// Provides extension CvMat conversion methods /// public static class CvMatTypeConversions { static Dictionary typeConversion = null; static CvMatTypeConversions() { typeConversion = new Dictionary(); typeConversion.Add(typeof(byte), CvMat.CvChannelDepth.CV_8U); typeConversion.Add(typeof(sbyte), CvMat.CvChannelDepth.CV_8S); typeConversion.Add(typeof(ushort), CvMat.CvChannelDepth.CV_16U); typeConversion.Add(typeof(short), CvMat.CvChannelDepth.CV_16S); typeConversion.Add(typeof(int), CvMat.CvChannelDepth.CV_32S); typeConversion.Add(typeof(float), CvMat.CvChannelDepth.CV_32F); typeConversion.Add(typeof(double), CvMat.CvChannelDepth.CV_64F); } /// /// Represents the existing image as CvMat structure where data is shared. /// /// Image. /// CvMat representation. public static CvMat AsCvMat(this IImage image) { var depthType = typeConversion[image.ColorInfo.ChannelType]; return CvMat.FromUserData(image.ImageData, image.Width, image.Height, image.Stride, depthType, image.ColorInfo.ChannelCount); } /// /// Copies data to managed array. /// /// Pixel color type. /// OpenCV matrix. /// Managed image representation. public static TColor[,] ToArray(this CvMat cvMat) where TColor: unmanaged, IColor { var im = new TColor[cvMat.Height, cvMat.Width]; using (var uIm = Image.Lock(im)) { Copy.UnsafeCopy2D(cvMat.ImageData, uIm.ImageData, cvMat.Step, uIm.Stride, uIm.Height); } return im; } } } ================================================ FILE: Source/Image/Interop/IplImage.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Collections.Generic; using System.Runtime.InteropServices; namespace DotImaging { /// /// Represents the OpenCV's IplImage structure which enables OpenCV / EmguCV interoperability. /// [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public unsafe struct IplImage { /// /// Constant for signed data types. /// public const uint IPL_DEPTH_SIGN = 0x80000000; /// /// Depth constants for IplImage channels. /// public enum IplChannelDepth : uint { /// /// Unsigned 1bit /// IPL_DEPTH_1U = 1, /// /// Unsigned 8-bit integer /// IPL_DEPTH_8U = 8, /// /// Signed 8-bit integer /// IPL_DEPTH_8S = (IPL_DEPTH_SIGN | 8), /// /// Unsigned 16-bit integer /// IPL_DEPTH_16U = 16, /// /// Signed 16-bit integer /// IPL_DEPTH_16S = (IPL_DEPTH_SIGN | 16), /// /// Signed 32-bit integer. /// IPL_DEPTH_32S = (IPL_DEPTH_SIGN | 32), /// /// Single-precision floating point /// IPL_DEPTH_32F = 32, /// /// Double-precision floating point /// IPL_DEPTH_64F = 64 } /// /// IplImage channel data order. /// public enum ChannelDataOrder : int { /// /// Interleaved color channels. /// INTERLEAVED = 0, /// /// Separate color channels. (CreateImage only creates images with interleaved channels.) /// SEPARATE = 1 } /// /// IplImage data origin. /// public enum DataOrigin : int { /// /// Data origin is located in the top-left corner. /// TopLeft = 0, /// /// Data origin is located in the bottom-left corner (Windows bitmap). /// BottomLeft = 1 } /// /// Size of the structure /// public int StructureSize; /// /// Version, always equal 0 /// public int ID; /// /// Number of channels. Most OpenCV functions support 1-4 channels. /// public int NumberOfChannels; /// /// Ignored by OpenCV (set to zero). /// public int AlphaChannel; /// /// Channel depth in bits + the optional sign bit /// public IplChannelDepth ChannelDepth; /// /// Ignored by OpenCV. The OpenCV function CvtColor requires the source and destination color spaces as parameters. /// public fixed byte ColorModel[4]; /// /// Ignored by OpenCV /// public fixed byte ChannelSeq[4]; /// /// Interleaved or separate (not used) channel order. /// public ChannelDataOrder DataOrder; /// /// Data origin: top-left or bottom-right (not used). /// public DataOrigin Origin; /// /// Alignment of image rows (4 or 8). (Ignored by OpenCV) /// public int Align; /// /// Image width /// public int Width; /// /// Image height /// public int Height; /// /// Region Of Interest (ROI). If not NULL, only this image region will be processed. /// It is always null if generic image is represented as OpenCV image. /// public IntPtr ROI; /// /// Must be NULL in OpenCV. /// public IntPtr MaskROI; /// /// Must be NULL in OpenCV. /// public IntPtr ImageId; /// /// Must be NULL in OpenCV. /// public IntPtr TileInfo; /// /// Image data size in bytes. /// public int ImageSize; /// /// A pointer to the aligned image data. /// public IntPtr ImageData; /// /// The size of an aligned image row, in bytes. /// public int WidthStep; /// /// Border completion mode, ignored by OpenCV. /// public fixed int BorderMode[4]; /// /// Border completion mode, ignored by OpenCV. /// public fixed int BorderConst[4]; /// /// A pointer to the origin of the image data (not necessarily aligned). This is used for image deallocation. /// During casting between generic image to OpenCV image it is set to null. /// public IntPtr ImageDataOrigin; internal IplImage(IImage image, Func translationFunc) { /************************ default values initialization *********************************/ this.StructureSize = sizeof(IplImage); this.ID = 0; this.Align = 4; this.AlphaChannel = 0; this.DataOrder = ChannelDataOrder.INTERLEAVED; this.Origin = DataOrigin.TopLeft; this.ROI = IntPtr.Zero; this.MaskROI = IntPtr.Zero; this.ImageId = IntPtr.Zero; this.TileInfo = IntPtr.Zero; this.ImageDataOrigin = IntPtr.Zero; //set to zero to avoid deallocation (should be equal to ImageData) /************************ default values initialization *********************************/ var colorInfo = image.ColorInfo; this.Align = (image.Stride % 8 == 0) ? 8 : (image.Stride % 4 == 0) ? 4 : 0; //TODO: check does OpenCV supports non-aligned images this.ChannelDepth = translationFunc(colorInfo.ColorType); this.NumberOfChannels = colorInfo.ChannelCount; this.Width = image.Width; this.Height = image.Height; this.WidthStep = image.Stride; this.ImageSize = image.Stride * image.Height; this.ImageData = image.ImageData; } /// /// Converts a pointer to an IplImage structure. /// /// /// public static IplImage FromPointer(IntPtr pointerToStructure) { if (pointerToStructure.Equals(IntPtr.Zero)) return default(IplImage); return (IplImage)Marshal.PtrToStructure(pointerToStructure, typeof(IplImage)); } } /// /// Contains methods for casting an generic image to an IplImage. /// public static class ImageOpenCVImageConversions { class IplColorInfo: IEquatable { public IplColorInfo(int channelCount, IplImage.IplChannelDepth channelDepth) { this.ChannelCount = channelCount; this.ChannelDepth = channelDepth; } public int ChannelCount { get; private set; } public IplImage.IplChannelDepth ChannelDepth { get; private set; } public bool Equals(IplColorInfo other) { if (other.ChannelCount == this.ChannelCount && other.ChannelDepth == this.ChannelDepth) return true; return false; } public override int GetHashCode() { return this.ChannelCount ^ (int)this.ChannelDepth; } } class GenericImageConstructor { public static GenericImageConstructor Create() where TColor: unmanaged, IColor { GenericImageConstructor ctor = new GenericImageConstructor(); ctor.ColorType = typeof(TColor); ctor.ToImage = (iplImage, destructor) => { if (destructor != null) return new Image(iplImage.ImageData, iplImage.Width, iplImage.Height, iplImage.WidthStep, iplImage, destructor); else return new Image(iplImage.ImageData, iplImage.Width, iplImage.Height, iplImage.WidthStep, iplImage); }; return ctor; } public Type ColorType { get; private set; } public Func, IImage> ToImage { get; private set; } private GenericImageConstructor() { } } static Dictionary colorAssociations; static Dictionary colorConstructorPairs; static ImageOpenCVImageConversions() { colorAssociations = new Dictionary(); //Gray colorAssociations.Add(typeof(Gray), new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_8S)); colorAssociations.Add(typeof(Gray), new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_8U)); colorAssociations.Add(typeof(Gray), new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_16S)); colorAssociations.Add(typeof(Gray), new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_16U)); colorAssociations.Add(typeof(Gray), new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_32S)); colorAssociations.Add(typeof(Gray), new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_32F)); colorAssociations.Add(typeof(Gray), new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_64F)); //Color2 - TODO ?? //Bgr colorAssociations.Add(typeof(Bgr), new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_8S)); colorAssociations.Add(typeof(Bgr), new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_8U)); colorAssociations.Add(typeof(Bgr), new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_16S)); colorAssociations.Add(typeof(Bgr), new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_16U)); colorAssociations.Add(typeof(Bgr), new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_32S)); colorAssociations.Add(typeof(Bgr), new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_32F)); colorAssociations.Add(typeof(Bgr), new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_64F)); //Bgra colorAssociations.Add(typeof(Bgra), new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_8S)); colorAssociations.Add(typeof(Bgra), new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_8U)); colorAssociations.Add(typeof(Bgra), new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_16S)); colorAssociations.Add(typeof(Bgra), new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_16U)); colorAssociations.Add(typeof(Bgra), new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_32S)); colorAssociations.Add(typeof(Bgra), new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_32F)); colorAssociations.Add(typeof(Bgra), new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_64F)); /****************************************************************************************/ colorConstructorPairs = new Dictionary(); //Gray colorConstructorPairs.Add(new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_8S), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_8U), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_16S), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_16U), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_32S), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_32F), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(1, IplImage.IplChannelDepth.IPL_DEPTH_64F), GenericImageConstructor.Create>()); //Color2 - TODO //Bgr colorConstructorPairs.Add(new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_8S), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_8U), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_16S), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_16U), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_32S), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_32F), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(3, IplImage.IplChannelDepth.IPL_DEPTH_64F), GenericImageConstructor.Create>()); //Bgra colorConstructorPairs.Add(new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_8S), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_8U), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_16S), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_16U), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_32S), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_32F), GenericImageConstructor.Create>()); colorConstructorPairs.Add(new IplColorInfo(4, IplImage.IplChannelDepth.IPL_DEPTH_64F), GenericImageConstructor.Create>()); } /// /// Casts an image to OpeCV image (IplImage). No data copy is involved. /// /// Generic image. /// OpeCV image format. public static IplImage AsCvIplImage(this IImage image) { return new IplImage(image, (channelType) => { /*if (image.IsOpenCVCompatibile() == false) throw new Exception("The image stride must be compatible to OpenCV image stride!");*/ IplColorInfo iplColorInfo; bool exist = colorAssociations.TryGetValue(channelType, out iplColorInfo); if (!exist) throw new Exception("The image can not be casted to IplImage because the image depth type is not supported by OpenCV!"); return iplColorInfo.ChannelDepth; }); } /// /// Casts iplImage in generic image representation. /// /// IplImage structure. /// Destructor which is called when created generic image is disposed. /// Image. public static unsafe IImage AsImage(this IplImage iplImage, Action destructor = null) { if (iplImage.Equals(default(IplImage))) return null; var imgCtorInfo = colorConstructorPairs[new IplColorInfo(iplImage.NumberOfChannels, iplImage.ChannelDepth)]; return imgCtorInfo.ToImage(iplImage, destructor); } } } ================================================ FILE: Source/Image/Linq/ImagingLinq.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Drawing; using System; using System.Collections.Generic; using System.Linq; namespace DotImaging.Linq { /// /// Contains 2D array Linq extensions /// public static partial class ImageLinqExtensions { /// /// Converts the specified collection to a 2D array determined by the specified size. /// The number of elements must match the number of elements in the collection. /// /// Element type /// Collection /// Array size /// 2D array public static T[,] ToArray2D(this IEnumerable collection, Size size) { return collection.ToArray2D(size.Width, size.Height); } /// /// Converts the specified collection to a 2D array determined by the specified size. /// The number of elements must match the number of elements in the collection. /// /// Element type /// Collection /// Array width /// Array height /// 2D array public static T[,] ToArray2D(this IEnumerable collection, int width, int height) { T[,] dest = new T[height, width]; int row = 0, col = 0; foreach (var item in collection) { dest[row, col] = item; col++; if (col >= width) { col = 0; row++; } } return dest; } /// /// Gets the 2x CPU number of slices which width is equal to array width. /// /// Element type /// Array /// Array slices public static IEnumerable> SliceUniform(this T[,] array) { int sliceCount = Environment.ProcessorCount * 2; int sliceHeight = array.Height() / sliceCount; int y = 0; Rectangle area = Rectangle.Empty; for (int sliceIdx = 0; sliceIdx < (sliceCount - 1); sliceIdx++) { area = new Rectangle(0, y, array.Width(), sliceHeight); y += sliceHeight; yield return new Slice2D(array, area); } //last slice area = new Rectangle(0, y, array.Width(), array.Height() - y); yield return new Slice2D(array, area); } /// /// Creates a parallel-ordered query of the array element collection. /// /// Element type /// Array /// Parallel-ordered query public static ParallelQuery AsParallelOrdered(this T[,] array) //slow { //return array.AsGrid().AsParallel().SelectMany(x => x.Array.AsEnumerable(x.Area)); return array.AsEnumerable().AsParallel().AsOrdered(); } /// /// Represents the specified array row as enumerable collection. /// /// Element type /// Array /// Row index /// Row elements public static IEnumerable Row(this T[,] array, int row) { var width = array.Width(); for (int col = 0; col < width; col++) { yield return array[row, col]; } } /// /// Represents the specified array column as enumerable collection. /// /// Element type /// Array /// Column index /// Column elements public static IEnumerable Column(this T[,] array, int column) { var height = array.Height(); for (int row = 0; row < height; row++) { yield return array[row, column]; } } /// /// Represents the specified array portion as enumerable collection. /// The scan path is from top-left -> bottom-right border. /// /// Element type /// Array /// Array portion /// Element collection public static IEnumerable AsEnumerable(this T[,] array, Rectangle area) { for (int row = area.Top; row < area.Bottom; row++) { for (int col = area.Left; col < area.Right; col++) { yield return array[row, col]; } } } /// /// Represents the specified array as enumerable collection. /// The scan path is from top-left -> bottom-right border. /// /// Element type. /// Array /// Element collection public static IEnumerable AsEnumerable(this T[,] array) { var area = new Rectangle(0, 0, array.Width(), array.Height()); return array.AsEnumerable(area); } /// /// Enumerates both arrays simultaneously and executes user-specified function. /// The scan path is from top-left -> bottom-right border. /// /// First data type. /// Second data type. /// Output type. /// First array. /// Second array. /// User specified function. /// Working area /// The result collection which elements are generated by using user-specified function. public static IEnumerable EnumerateWith(this TFirst[,] first, TSecond[,] second, Func function, Rectangle area) { if (first.Width() < area.Right || first.Height() < area.Bottom || second.Width() < area.Right || second.Height() < area.Bottom || area.Left < 0 || area.Top < 0) { throw new ArgumentOutOfRangeException(nameof(area), "The specified area must be witihin the images."); } for (int row = area.Top; row < area.Bottom; row++) { for (int col = area.Left; col < area.Right; col++) { yield return function(first[row, col], second[row, col]); } } } /// /// Enumerates both arrays simultaneously and executes user-specified function. /// The scan path is from top-left -> bottom-right border. /// /// First data type. /// Second data type. /// Output type. /// First array. /// Second array. /// User specified function. /// The result collection which elements are generated by using user-specified function. public static IEnumerable EnumerateWith(this TFirst[,] first, TSecond[,] second, Func function) { if (first.Width() != second.Width() || first.Height() != second.Height()) { throw new ArgumentException("Image sizes must be the same."); } Rectangle area = new Rectangle(Point.Empty, first.Size()); return EnumerateWith(first, second, function, area); } } } ================================================ FILE: Source/Image/ParallelLauncher.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Runtime.CompilerServices; namespace DotImaging { /// /// Kernel thread structure which represents the working point. /// public struct KernelThread { /// /// Horizontal offset. /// public int X; /// /// Vertical offset. /// public int Y; } /// /// Provides a launch method and extension methods for parallel array processing. /// public static class ParallelLauncher { /// /// launches the specified kernel function in parallel. /// /// Array element type. /// Array. /// Kernel function. /// Horizontal grid size. /// Vertical grid size [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Launch(this T[,] array, Action kernel, int gridX, int gridY) { Launch(thread => { kernel(thread, array); }, gridX, gridY); } /// /// Launches the specified kernel function in parallel. /// /// Kernel function. /// Horizontal grid size. /// Vertical grid size [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Launch(Action kernel, int gridX, int gridY) { System.Threading.Tasks.Parallel.For(0, gridY, (j) => { KernelThread th = new KernelThread(); th.Y = j; for (int i = 0; i < gridX; i++) { th.X = i; kernel(th); } }); } } } ================================================ FILE: Source/Image/Slice2D.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Drawing; namespace DotImaging { /// /// A wrapper for 2D sub-array. /// /// Element type. public class Slice2D { /// /// Creates a new grid from the specified array. /// /// Array. public Slice2D(T[,] array) { this.Array = array; this.Area = new Rectangle(0, 0, array.Width(), array.Height()); } /// /// Creates a new grid from the specified array. /// /// Array. /// Sub-array area. public Slice2D(T[,] array, Rectangle area) { this.Array = array; this.Area = area; } /// /// Gets the original array. /// public T[,] Array { get; private set; } /// /// Gets the working array area. /// public Rectangle Area { get; private set; } /// /// Gets or sets the specified value. /// /// Offset from the upper-left y area location. /// Offset from the upper-left x area location. /// Value. public T this[int y, int x] { get { return Array[Area.Y + y, Area.X + x]; } set { Array[Area.Y + y, Area.X + x] = value; } } /// /// Converts the array into grid representation. /// /// Array. /// Grid. public static implicit operator Slice2D(T[,] array) { return new Slice2D(array); } /// /// Determines whether the specified object is equal to the current object. /// /// Other object /// True if two objects are equal, false otherwise. public override bool Equals(object other) { var otherObj = other as Slice2D; if (otherObj == null) return false; if(this.Array.Equals(otherObj.Array) && this.Area.Equals(otherObj.Area)) return true; else return false; } /// /// Serves as a hash function for a particular type. /// /// A hash code for the current object. public override int GetHashCode() { return base.GetHashCode(); } } /// /// Provides extensions for . /// public static class Slice2DExtensions { /// /// Clones the portion of the array defined by the provided slice. /// /// Value, blittable type. /// Slice. /// Cloned portion of the array. public static unsafe T[,] Clone(this Slice2D slice) where T : unmanaged { T[,] patch = null; using (var uSrc = slice.Array.Lock(slice.Area)) { patch = uSrc.Clone(); } return patch; } } } ================================================ FILE: Source/Image/Unmanaged/IImage.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Drawing; namespace DotImaging { /// /// Represents interface to the class. /// public interface IImage: IDisposable, IEquatable { /// /// Gets unmanaged image data. /// IntPtr ImageData { get; } /// /// Gets image width. /// int Width { get; } /// /// Gets image height. /// int Height { get; } /// /// Gets image stride. /// int Stride { get; } /// /// Gets image size. /// Size Size { get; } /// /// Gets image color info. /// ColorInfo ColorInfo { get; } /// /// Gets image data at specified location. /// /// Row index. /// Column index. /// Data pointer. IntPtr GetData(int row, int col); /// /// Gets image data at specified location. /// /// Row index. /// Data pointer. IntPtr GetData(int row); /// /// Gets sub-image from specified area. Data is shared. /// /// Area of an image for sub-image creation. /// Sub-image. IImage GetSubRect(Rectangle rect); } } ================================================ FILE: Source/Image/Unmanaged/Image'1.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Drawing; using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace DotImaging { /// /// Implements generic image type and provides a basic data manipulation. Other functions are built as extensions making the class light-weight and portable. /// Other extensions and satellite assemblies enables multiple interoperability with other libraries such as AForge.NET, OpenCV, EmguCV. /// /// Color type. The structure must be blittable. public class Image : IImage, IEquatable, IDisposable where TColor: unmanaged { #region Constructor methods object objectReference = null; //prevents disposing parent object if sharing data (GetSubRect(..), casting...) Action parentDestructor = null; private Image() { this.ColorInfo = ColorInfo.GetInfo(); //an early init is needed during deserialization } /// /// Creates an unmanaged image by pinning the provided array. /// No data is copied. /// /// Array to lock. /// Unmanaged image. public static Image Lock(TColor[,] array) { GCHandle handle = GCHandle.Alloc(array, GCHandleType.Pinned); int width = array.GetLength(1); int height = array.GetLength(0); var image = new Image(handle.AddrOfPinnedObject(), width, height, ColorInfo.GetInfo().Size * width, handle, x => ((GCHandle)x).Free()); return image; } /// /// Creates an unmanaged image representation from the provided array and image width (un-flattens the array). /// No data is copied. /// /// Raw-byte image data array to lock. /// /// Image width. /// Data length and the provided width must produce an integer height. /// /// Unmanaged image. public static Image Lock(byte[] rawImageArray, int width) { GCHandle handle = GCHandle.Alloc(rawImageArray, GCHandleType.Pinned); float height = (float)rawImageArray.Length / (width * ColorInfo.GetInfo().Size); if (height != (int)height) throw new ArgumentException("The calculated height is not integer. There is a mismatch between given width, the data length and the image pixel type."); var image = new Image(handle.AddrOfPinnedObject(), width, (int)height, ColorInfo.GetInfo().Size * width, handle, x => ((GCHandle)x).Free()); return image; } /// /// Constructs an image from unmanaged data. Data is shared. /// /// Pointer to unmanaged data. /// Image width. /// Image height. /// Image stride. /// To prevent object from deallocating use this parameter. /// If a parent needs to be destroyed or release use this function. (e.g. unpin object - GCHandle) public Image(IntPtr imageData, int width, int height, int stride, object parentReference = null, Action parentDestructor = null) :this() { initializeProperties(this, imageData, width, height, stride); this.objectReference = parentReference; this.parentDestructor = parentDestructor; } private static void initializeProperties(Image im, IntPtr imageData, int width, int height, int stride) { im.ImageData = imageData; im.Width = width; im.Height = height; im.Stride = stride; } #endregion #region Properties /// /// Gets unmanaged image data. /// public IntPtr ImageData { get; private set; } /// /// Gets image width. /// public int Width { get; private set; } /// /// Gets image height. /// public int Height { get; private set; } /// /// Gets image stride - number of bytes per image row. /// public int Stride { get; private set; } /// /// Gets image size. /// public Size Size { get { return new Size(this.Width, this.Height); } } /// /// Gets image color info. /// public ColorInfo ColorInfo { get; protected set; } //set in #endregion #region Basic helper methods /// /// Gets image data at specified location. /// /// Row index. /// Column index. /// Data pointer. [MethodImpl(MethodImplOptions.AggressiveInlining)] public IntPtr GetData(int row, int col) { if (col < 0 || col >= this.Width) throw new ArgumentOutOfRangeException("Column index is out of range: " + col); return this.GetData(row) + col * this.ColorInfo.Size; } /// /// Gets image data at specified location. /// /// Row index. /// Data pointer. [MethodImpl(MethodImplOptions.AggressiveInlining)] public IntPtr GetData(int row) { if (row < 0 || row >= this.Height) throw new ArgumentOutOfRangeException("Row index is out of range: " + row); return this.ImageData + row * this.Stride; } /// /// Gets sub-image from specified area. Data is shared. /// /// Area of an image for sub-image creation. /// Sub-image. public Image GetSubRect(Rectangle rect) { if (rect.Right > this.Width || rect.Bottom > this.Height) //Location will be verified through GetData(...) function throw new ArgumentOutOfRangeException(); object objRef = this.objectReference ?? this; //always show at the root IntPtr data = GetData(rect.Y, rect.X); return new Image(data, rect.Width, rect.Height, this.Stride, objRef); } /// /// Gets sub-image from specified area. Data is shared. /// /// Area of an image for sub-image creation. /// Sub-image. IImage IImage.GetSubRect(Rectangle rect) { return this.GetSubRect(rect); } #endregion #region IEquatable, IDisposable /// /// Compares this image to another image. Only pointer location and image size are compared. /// There is no data compassion. /// /// Other image. /// Whether two images are equal or not. public bool Equals(IImage other) { if (other != null && this.ImageData == other.ImageData && this.Size == other.Size) { return true; } return false; } /// /// Compares this image to another object. Internally the function overload is called. /// /// Other. /// Is the image equal to an object or not. public override bool Equals(object obj) { return this.Equals(obj as IImage); } /// /// Image's hash code. Pointer address is used as hash code. /// /// Image's hash code. public override int GetHashCode() { unchecked { return (int)this.ImageData.ToInt64(); //support for 64-bit architecture } } bool isDisposed = false; /// /// Disposes generic image. /// In case if data is allocated it is released. /// If data is shared parent reference (if exists) and parent handle (if exist) is released. /// public void Dispose() { if (isDisposed) return; //if this function is called for the first time if (this.parentDestructor != null) this.parentDestructor(objectReference); this.parentDestructor = null; this.objectReference = null; isDisposed = true; } /// /// Disposes the image. /// ~Image() { Dispose(); } #endregion } } ================================================ FILE: Source/Primitives2D/Box2D/Box2D.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2018 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Linq; using System.Runtime.InteropServices; using System.Drawing; namespace DotImaging.Primitives2D { /// /// Box2D equivalent of OpenCV's Box2D Class. /// [StructLayout(LayoutKind.Sequential)] public struct Box2D { /// /// Gets empty structure. /// public static readonly Box2D Empty = new Box2D(); /// /// Area center. /// public PointF Center; /// /// Area size. /// public SizeF Size; /// /// Angle in degrees. /// public float Angle; /// /// Creates new structure from area and angle. /// /// Area. /// Angle in degrees. public Box2D(RectangleF rect, float angle) :this(rect.Center(), rect.Size, angle) {} /// /// Creates new structure from area and angle. /// /// Box2D center. /// Box 2D size. /// Angle in degrees. public Box2D(PointF center, SizeF size, float angle) { this.Center = new PointF(center.X, center.Y); this.Size = size; this.Angle = angle; } /// /// Returns true if the structure is empty. /// public bool IsEmpty { get { return this.Equals(Empty); } } /// /// Gets the minimum enclosing rectangle for this box. /// public RectangleF GetMinArea() { var vertices = this.GetVertices(); float minX = vertices.Min(x => x.X); float maxX = vertices.Max(x => x.X); float minY = vertices.Min(x => x.Y); float maxY = vertices.Max(x => x.Y); return new RectangleF(minX, minY, maxX - minX, maxY - minY); } /// /// Gets vertices. /// /// Vertices. public PointF[] GetVertices() { PointF center = this.Center; var angleDeg = this.Angle; PointF[] nonRotatedVertices = getNonRotatedVertices(); PointF[] rotatedVertices = nonRotatedVertices.Select(x=> new PointF(x.X - center.X, x.Y - center.Y)) //translate to (0,0) .Select(x => x.Rotate(angleDeg)) //rotate .Select(x => new PointF(x.X + center.X, x.Y + center.Y)) //translate back .ToArray(); return rotatedVertices; } private PointF[] getNonRotatedVertices() { float offsetX = this.Size.Width / 2; float offsetY = this.Size.Height / 2; return new PointF[] { new PointF(this.Center.X - offsetX, this.Center.Y - offsetY), //left-upper new PointF(this.Center.X + offsetX, this.Center.Y - offsetY), //right-upper new PointF(this.Center.X + offsetX, this.Center.Y + offsetY), //right-bottom new PointF(this.Center.X - offsetX, this.Center.Y + offsetY) //left-bottom }; } /// /// Converts Rectangle to the Box2D representation (angle is zero). /// /// Rectangle to convert. /// Box2D representation. public static implicit operator Box2D(Rectangle rect) { return new Box2D(rect, 0); } /// /// Converts RectangleF to the Box2D representation (angle is zero). /// /// Rectangle to convert. /// Box2D representation. public static implicit operator Box2D(RectangleF rect) { return new Box2D(rect, 0); } /// /// Determines whether two objects are equal. /// /// Object to test. /// True if two objects are equal, false otherwise. public override bool Equals(object obj) { if (obj is Box2D == false) return false; var b = (Box2D)obj; return b.Center.Equals(this.Center) && b.Angle.Equals(this.Angle); } /// /// Gets hash-code for the structure. /// /// Hash-code. public override int GetHashCode() { return base.GetHashCode(); } } } ================================================ FILE: Source/Primitives2D/Circle/Circle.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2018 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion namespace DotImaging.Primitives2D { // Accord Math Library // The Accord.NET Framework // http://accord-framework.net // // Copyright © César Souza, 2009-2014 // cesarsouza at gmail.com // // Copyright © Darko Jurić, 2014-2019 // darko.juric2 at gmail.com // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // using System.Drawing; /// /// 2D circle class. /// public struct Circle { /// /// Horizontal center coordinate. /// public int X; /// /// Vertical center coordinate. /// public int Y; /// /// Circle radius. /// public int Radius; /// /// Gets or sets circle's location. /// public Point Center { get { return new Point(X, Y); } set { this.X = value.X; this.Y = value.Y; } } /// /// Creates a new instance of an structure. /// /// Center position. /// Circle radius. public Circle(Point position, int radius) :this(position.X, position.Y, radius) {} /// /// Creates a new instance of an structure. /// /// Horizontal center position. /// Vertical center position. /// Circle radius. public Circle(int x, int y, int radius) { this.X = x; this.Y = y; this.Radius = radius; } /// /// Gets the area of the circle (πR²). /// /// public double Area { get { return Radius * Radius * System.Math.PI; } } /// /// Gets the circumference of the circle (2πR). /// /// public double Circumference { get { return 2 * Radius * System.Math.PI; } } /// /// Gets the diameter of the circle (2R). /// /// public int Diameter { get { return 2 * Radius; } } /// /// Computes the distance from circle to point. /// /// /// The point to have its distance from the circle computed. /// /// The distance from to this circle. /// public double DistanceToPoint(Point point) { var centerDiff = this.Center.DistanceTo(point); return System.Math.Abs(centerDiff - Radius); } /// /// Converts integer into floating-point representation. /// /// Integer circle representation. /// Floating-point circle representation. public static implicit operator CircleF(Circle circle) { return new CircleF(circle.X, circle.Y, circle.Radius); } } } ================================================ FILE: Source/Primitives2D/Circle/CircleF.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2018 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion namespace DotImaging.Primitives2D { // Accord Math Library // The Accord.NET Framework // http://accord-framework.net // // Copyright © César Souza, 2009-2014 // cesarsouza at gmail.com // // Copyright © Darko Jurić, 2014-2019 // darko.juric2 at gmail.com // // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // using System.Drawing; /// /// 2D circle class. /// public struct CircleF { /// /// Horizontal center coordinate. /// public float X; /// /// Vertical center coordinate. /// public float Y; /// /// Circle radius. /// public float Radius; /// /// Gets or sets circle's location. /// public PointF Center { get { return new PointF(X, Y); } set { this.X = value.X; this.Y = value.Y; } } /// /// Creates a new instance of an structure. /// /// Center position. /// Circle radius. public CircleF(PointF position, float radius) : this(position.X, position.Y, radius) { } /// /// Creates a new instance of an structure. /// /// Horizontal center position. /// Vertical center position. /// Circle radius. public CircleF(float x, float y, float radius) { this.X = x; this.Y = y; this.Radius = radius; } /// /// Gets the area of the circle (πR²). /// /// public double Area { get { return Radius * Radius * System.Math.PI; } } /// /// Gets the circumference of the circle (2πR). /// /// public double Circumference { get { return 2 * Radius * System.Math.PI; } } /// /// Gets the diameter of the circle (2R). /// /// public float Diameter { get { return 2 * Radius; } } /// /// Creates a new from three non-linear points. /// /// /// The first point. /// The second point. /// The third point. /// public CircleF(PointF p1, PointF p2, PointF p3) { // ya = ma * (x - x1) + y1 // yb = mb * (x - x2) + y2 // // ma = (y2 - y1) / (x2 - x1) // mb = (y3 - y2) / (x3 - x2) double ma = (p2.Y - p1.Y) / (p2.X - p1.X); double mb = (p3.Y - p2.Y) / (p3.X - p2.X); // (ma * mb * (y1 - y3) + mb * (x1 + x2) - ma * (x2 + x3) // x = ---------------------------------------------------------- // 2 * (mb - ma) double x = (ma * mb * (p1.Y - p3.Y) + mb * (p1.X + p2.Y) - ma * (p2.X + p3.X)) / (2 * (mb - ma)); double y = ma * (x - p1.X) + p1.Y; this.X = (float)x; this.Y = (float)y; this.Radius = (float)System.Math.Sqrt((this.X - p1.X) * (this.X - p1.X) + (this.Y - p1.Y) * (this.Y - p1.Y)); //Euclidean distance } /// /// Computes the distance from circle to point. /// /// /// The point to have its distance from the circle computed. /// /// The distance from to this circle. /// public double DistanceToPoint(PointF point) { var centerDiff = this.Center.DistanceTo(point); return System.Math.Abs(centerDiff - Radius); } } } ================================================ FILE: Source/Primitives2D/Ellipse/Ellipse.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2018 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Runtime.InteropServices; using System.Drawing; namespace DotImaging.Primitives2D { /// /// Ellipse structure containing center and ellipse size. /// [StructLayout(LayoutKind.Sequential)] public struct Ellipse { /// /// Creates a new ellipse. /// /// Ellipse center. /// Ellipse size. /// Angle in degrees. public Ellipse(PointF center, SizeF size, float angle = 0) { this.Center = center; this.Size = size; this.Angle = angle; } /// /// Area center. /// public PointF Center; /// /// Area size. /// public SizeF Size; /// /// Angle in degrees. /// public float Angle; /// /// Converts Box2D to Ellipse representation. /// /// Box to convert. /// Ellipse. public static explicit operator Ellipse(Box2D box) { return new Ellipse { Center = box.Center, Size = box.Size, Angle = box.Angle }; } /// /// Converts Ellipse to Box2D representation. /// /// Ellipse to convert. /// Box2D. public static explicit operator Box2D(Ellipse ellipse) { return new Box2D { Center = ellipse.Center, Size = ellipse.Size, Angle = ellipse.Angle }; } /// /// Fits the covariance matrix (or 2nd moment matrix) to the ellipse by calculating eigen-vectors and values. /// /// Covariance matrix (or 2nd moment matrix). /// Center of the ellipse. /// Ellipse. public static Ellipse Fit(double[,] covMatrix, PointF center = default(PointF)) { if (covMatrix.GetLength(0) != 2 || covMatrix.GetLength(1) != 2) throw new ArgumentException("Covariance matrix must have the same dimensions, and the dimension length must be 2!"); return Fit(covMatrix[0, 0], covMatrix[0, 1], covMatrix[1, 1], center); } /// /// Fits the covariance matrix (or 2nd moment matrix) to the ellipse by calculating eigen-vectors and values. /// /// [0, 0] value of the covariance matrix. /// [0, 1] or [1, 0] value of the covariance matrix. /// [1, 1] value of the covariance matrix. /// Center of the ellipse. /// Returns true if both calculated eigen-values are positive. /// Ellipse. public static Ellipse Fit(double a, double b, double c, PointF center, out bool success) { var acDiff = a - c; var acSum = a + c; //A * X = lambda * X => solve quadratic equation => lambda1/2 = [a + c +/- sqrt((a-c)^2 + 4b^2)] / 2 var sqrtDiscriminant = System.Math.Sqrt(acDiff * acDiff + 4 * b * b); var eigVal1 = (acSum + sqrtDiscriminant) / 2; var eigVal2 = (acSum - sqrtDiscriminant) / 2; //A * X = lambda * X => y / x = b / (lambda - c); where lambda is the first eigen-value var angle = System.Math.Atan2(2 * b, (acDiff + sqrtDiscriminant)); success = eigVal1 > 0 && eigVal2 > 0; return new Ellipse { Center = center, Size = new SizeF { Width = (float)System.Math.Sqrt(eigVal1) * 4, Height =(float)System.Math.Sqrt(eigVal2) * 4 }, Angle = (float)(angle * 180 / Math.PI) }; } /// /// Fits the covariance matrix (or 2nd moment matrix) to the ellipse by calculating eigen-vectors and values. /// /// [0, 0] value of the covariance matrix. /// [0, 1] or [1, 0] value of the covariance matrix. /// [1, 1] value of the covariance matrix. /// Center of the ellipse. /// Ellipse. public static Ellipse Fit(double a, double b, double c, PointF center = default(PointF)) { bool success; return Fit(a, b, c, center, out success); } } } ================================================ FILE: Source/Primitives2D/Point/Point'1.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2018 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion namespace DotImaging.Primitives2D { /// /// Represents the 2D (X, Y) pair. /// /// Value type. public struct Point where T : struct { /// /// Creates a new point. /// /// X coordinate. /// Y coordinate. public Point(T x, T y) { X = x; Y = y; } /// /// Gets or sets X coordinate. /// public T X; /// /// Gets or sets Y coordinate. /// public T Y; /// /// Determines whether the provided object is equal to the current object. /// /// Other object to compare with. /// True if the two objects are equal, false otherwise. public override bool Equals(object obj) { if (obj is Point == false) return false; var pt = (Point)obj; return this.X.Equals(pt.X) && this.Y.Equals(pt.Y); } /// /// Gets the hash code. /// /// Hash code. public override int GetHashCode() { return this.X.GetHashCode() ^ this.Y.GetHashCode(); } /// /// Gets the string representation of the object. /// /// String representation. public override string ToString() { return string.Format("{{X={0}, Y={1}}}", X, Y); } } } ================================================ FILE: Source/Primitives2D/Point/PointExtensions.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2018 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Collections.Generic; using System.Linq; using System.Drawing; namespace DotImaging.Primitives2D { /// /// Provides point extension methods. /// public static class Point32iExtensions { /// /// Transforms point to the lower pyramid level. /// /// Point. /// Specifies how many levels to take. /// Specifies the pyramid scale factor. /// Scaled point. public static PointF UpScale(this Point p, int levels = 1, double factor = 2) { var upscaleFactor = (float)System.Math.Pow(factor, levels); return new PointF { X = p.X * upscaleFactor, Y = p.Y * upscaleFactor }; } /// /// Transforms point to the higher pyramid level. /// /// Point. /// Specifies how many levels to take. /// Specifies the pyramid scale factor. /// Scaled point. public static PointF DownScale(this Point p, int levels = 1, double factor = 2) { var downscaleFactor = (float)(1 / System.Math.Pow(factor, levels)); return new PointF { X = p.X * downscaleFactor, Y = p.Y * downscaleFactor }; } /// /// Translates the point by the specified offset. /// /// The point to offset. /// Offset to be added. /// Translated point. public static Point Add(this Point point, Point offset) { return new Point { X = point.X + offset.X, Y = point.Y + offset.Y }; } /// /// Subtracts the point by the specified offset. /// /// The point to subtract. /// Subtract factor. /// Translated point. public static Point Subtract(this Point point, Point offset) { return new Point { X = point.X - offset.X, Y = point.Y - offset.Y }; } /// /// Calculates the Euclidean distance between two points. /// /// First point. /// Second point. /// Euclidean distance between the points. public static double DistanceTo(this Point pointA, Point pointB) { var distnace = System.Math.Sqrt((pointA.X - pointB.X) * (pointA.X - pointB.X) + (pointA.Y - pointB.Y) * (pointA.Y - pointB.Y)); //Euclidean distance return distnace; } /// /// Rotates one point around another /// /// The point to rotate. /// The rotation angle in degrees. /// The center point of rotation. /// Rotated point public static PointF Rotate(this Point pointToRotate, double angleDeg, Point centerPoint) { //taken from: http://stackoverflow.com/questions/13695317/rotate-a-point-around-another-point and modified double angleInRadians = angleDeg * (Math.PI / 180); double cosTheta = Math.Cos(angleInRadians); double sinTheta = Math.Sin(angleInRadians); return new PointF { X = (float) (cosTheta * (pointToRotate.X - centerPoint.X) - sinTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.X), Y = (float) (sinTheta * (pointToRotate.X - centerPoint.X) + cosTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.Y) }; } /// /// Rotates one point around the (0,0). /// /// The point to rotate. /// The rotation angle in degrees. /// Rotated point public static PointF Rotate(this Point pointToRotate, double angleDeg) { return pointToRotate.Rotate(angleDeg, Point.Empty); } /// /// Negates point coordinates. /// /// The point to negate. /// Point with negated coordinates. public static Point Negate(this Point point) { return new Point { X = -point.X, Y = -point.Y }; } } /// /// Provides point extension methods. /// public static class Point32fExtensions { /// /// Transforms point to the lower pyramid level. /// /// Point. /// Specifies how many levels to take. /// Specifies the pyramid scale factor. /// Scaled point. public static PointF UpScale(this PointF p, int levels = 1, double factor = 2) { var upscaleFactor = (float)System.Math.Pow(factor, levels); return new PointF { X = p.X * upscaleFactor, Y = p.Y * upscaleFactor }; } /// /// Transforms point to the higher pyramid level. /// /// Point. /// Specifies how many levels to take. /// Specifies the pyramid scale factor. /// Scaled point. public static PointF DownScale(this PointF p, int levels = 1, double factor = 2) { var downscaleFactor = (float)(1 / System.Math.Pow(factor, levels)); return new PointF { X = p.X * downscaleFactor, Y = p.Y * downscaleFactor }; } /// /// Translates the point by the specified offset. /// /// The point to offset. /// Offset to be added. /// Translated point. public static PointF Add(this PointF point, PointF offset) { return new PointF { X = point.X + offset.X, Y = point.Y + offset.Y }; } /// /// Subtracts the point by the specified offset. /// /// The point to subtract. /// Subtract factor. /// Translated point. public static PointF Subtract(this PointF point, PointF offset) { return new PointF { X = point.X - offset.X, Y = point.Y - offset.Y }; } /// /// Calculates the Euclidean distance between two points. /// /// First point. /// Second point. /// Euclidean distance between the points. public static double DistanceTo(this PointF pointA, PointF pointB) { var distnace = System.Math.Sqrt((pointA.X - pointB.X) * (pointA.X - pointB.X) + (pointA.Y - pointB.Y) * (pointA.Y - pointB.Y)); //Euclidean distance return distnace; } /// /// Rotates one point around another /// /// The point to rotate. /// The rotation angle in degrees. /// The center point of rotation. /// Rotated point public static PointF Rotate(this PointF pointToRotate, double angleDeg, PointF centerPoint) { //taken from: http://stackoverflow.com/questions/13695317/rotate-a-point-around-another-point and modified double angleInRadians = angleDeg * (Math.PI / 180); double cosTheta = Math.Cos(angleInRadians); double sinTheta = Math.Sin(angleInRadians); return new PointF { X = (float) (cosTheta * (pointToRotate.X - centerPoint.X) - sinTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.X), Y = (float) (sinTheta * (pointToRotate.X - centerPoint.X) + cosTheta * (pointToRotate.Y - centerPoint.Y) + centerPoint.Y) }; } /// /// Rotates one point around the (0,0). /// /// The point to rotate. /// The rotation angle in degrees. /// Rotated point public static PointF Rotate(this PointF pointToRotate, double angleDeg) { return pointToRotate.Rotate(angleDeg, PointF.Empty); } /// /// Rounds point coordinates. /// /// Point. /// Integer point with rounded coordinates. public static Point Round(this PointF point) { return Point.Round(point); } /// /// Gets integer point representation by applying floor operation. /// /// Point to truncate. /// Truncated point. public static Point Floor(this PointF p) { return new Point { X = (int)p.X, Y = (int)p.Y }; } /// /// Negates point coordinates. /// /// The point to negate. /// Point with negated coordinates. public static PointF Negate(this PointF point) { return new PointF { X = -point.X, Y = -point.Y }; } } /// /// Provides point collection extensions. /// public static class Point32fCollectionExtensions { //taken from:http://stackoverflow.com/questions/4243042/c-sharp-point-in-polygon and modified /// /// Checks whether the specified location is in the polygon. /// /// Polygon. /// Horizontal coordinate. /// VErtical coordinate. /// True if the point resides inside the polygon, false otherwise. public static bool IsInPolygon(this IList poly, float x, float y) { PointF p1, p2; bool inside = false; if (poly.Count < 3) { return inside; } var oldPoint = new PointF(poly[poly.Count - 1].X, poly[poly.Count - 1].Y); for (int i = 0; i < poly.Count; i++) { var newPoint = new PointF(poly[i].X, poly[i].Y); if (newPoint.X > oldPoint.X) { p1 = oldPoint; p2 = newPoint; } else { p1 = newPoint; p2 = oldPoint; } if ((newPoint.X < x) == (x <= oldPoint.X) && (y - (long)p1.Y) * (p2.X - p1.X) < (p2.Y - (long)p1.Y) * (x - p1.X)) { inside = !inside; } oldPoint = newPoint; } return inside; } /// /// Gets the minimum bounding rectangle around the points. /// /// Contour points. /// Bounding rectangle. public static RectangleF BoundingRect(this IEnumerable points) { if (points.Any() == false) return RectangleF.Empty; float minX = Single.MaxValue, maxX = Single.MinValue, minY = Single.MaxValue, maxY = Single.MinValue; foreach (var pt in points) { if (pt.X < minX) minX = pt.X; if (pt.X > maxX) maxX = pt.X; if (pt.Y < minY) minY = pt.Y; if (pt.Y > maxY) maxY = pt.Y; } return new RectangleF(minX, minY, maxX - minX, maxY - minY); } /// /// Gets the center of the mass of the contour. /// /// Contour points. /// The center of the mass of the contour. public static PointF Center(this IEnumerable points) { PointF average = new PointF(); int nSamples = 0; foreach (var pt in points) { average.X += pt.X; average.Y += pt.Y; nSamples++; } average.X /= nSamples; average.Y /= nSamples; return average; } /// /// Determines whether the polygon forms rectangle. /// /// Polygon. /// True if the polygon forms rectangle, false otherwise. public static bool IsRectangle(this IEnumerable points) { if (points.Count() != 4) return false; var rect = points.BoundingRect(); bool hasTopLeft = false, hasTopRight = false, hasBottomLeft = false, hasBottomRight = false; foreach (var pt in points) { if (rect.Top == pt.Y) { if (rect.X == pt.X) hasTopLeft = true; if (rect.Right == pt.X) hasTopRight = true; } if (rect.Bottom == pt.Y) { if (rect.X == pt.X) hasBottomLeft = true; if (rect.Right == pt.X) hasBottomRight = true; } } return hasTopLeft && hasTopRight && hasBottomLeft && hasBottomRight; } } /// /// Provides point collection extensions. /// public static class Point32iCollectionExtensions { //taken from:http://stackoverflow.com/questions/4243042/c-sharp-point-in-polygon and modified /// /// Checks whether the specified location is in the polygon. /// /// Polygon. /// Horizontal coordinate. /// VErtical coordinate. /// True if the point resides inside the polygon, false otherwise. public static bool IsInPolygon(this IList poly, float x, float y) { Point p1, p2; bool inside = false; if (poly.Count < 3) { return inside; } var oldPoint = new Point(poly[poly.Count - 1].X, poly[poly.Count - 1].Y); for (int i = 0; i < poly.Count; i++) { var newPoint = new Point(poly[i].X, poly[i].Y); if (newPoint.X > oldPoint.X) { p1 = oldPoint; p2 = newPoint; } else { p1 = newPoint; p2 = oldPoint; } if ((newPoint.X < x) == (x <= oldPoint.X) && (y - (long)p1.Y) * (p2.X - p1.X) < (p2.Y - (long)p1.Y) * (x - p1.X)) { inside = !inside; } oldPoint = newPoint; } return inside; } /// /// Gets the minimum bounding rectangle around the points. /// /// Contour points. /// Bounding rectangle. public static Rectangle BoundingRect(this IEnumerable points) { if (points.Any() == false) return Rectangle.Empty; int minX = Int32.MaxValue, maxX = Int32.MinValue, minY = Int32.MaxValue, maxY = Int32.MinValue; foreach (var pt in points) { if (pt.X < minX) minX = pt.X; if (pt.X > maxX) maxX = pt.X; if (pt.Y < minY) minY = pt.Y; if (pt.Y > maxY) maxY = pt.Y; } return new Rectangle(minX, minY, maxX - minX, maxY - minY); } /// /// Gets the center of the mass of the contour. /// /// Contour points. /// The center of the mass of the contour. public static PointF Center(this IEnumerable points) { PointF average = new PointF(); int nSamples = 0; foreach (var pt in points) { average.X += pt.X; average.Y += pt.Y; nSamples++; } average.X /= nSamples; average.Y /= nSamples; return average; } /// /// Determines whether the polygon forms rectangle. /// /// Polygon. /// True if the polygon forms rectangle, false otherwise. public static bool IsRectangle(this IEnumerable points) { if (points.Count() != 4) return false; var rect = points.BoundingRect(); bool hasTopLeft = false, hasTopRight = false, hasBottomLeft = false, hasBottomRight = false; foreach (var pt in points) { if (rect.Top == pt.Y) { if (rect.X == pt.X) hasTopLeft = true; if (rect.Right == pt.X) hasTopRight = true; } if (rect.Bottom == pt.Y) { if (rect.X == pt.X) hasBottomLeft = true; if (rect.Right == pt.X) hasBottomRight = true; } } return hasTopLeft && hasTopRight && hasBottomLeft && hasBottomRight; } } } ================================================ FILE: Source/Primitives2D/Primitives2D.csproj ================================================  netcoreapp2.2 DotImaging.Primitives2D DotImaging bin\DotImaging.Primitives2D.xml true 5.3.0 DotImaging.Primitives2D Point, Size, Rectangle extensions, Circle, Ellipse, Box2D. imaging geometry structures 2D Darko Jurić Darko Jurić https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Licence.txt https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Logo/logo-small.png https://raw.githubusercontent.com/dajuric/dot-imaging/ https://raw.githubusercontent.com/dajuric/dot-imaging/ true ../../Deploy/NuGet/bin/ ================================================ FILE: Source/Primitives2D/Rectangle/RectangleExtensions.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2018 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Collections.Generic; using System.Drawing; namespace DotImaging.Primitives2D { /// /// Provides extension methods for Rectangle and RectangleF structures. /// public static class RectangleExtennsions { /// /// Gets intersection percent of two rectangles. /// /// First rectangle. /// Second rectangle. /// Intersection percent (e.g. 1 - full intersection, 0 - no intersection). public static float IntersectionPercent(this Rectangle rect1, Rectangle rect2) { return RectangleFExtensions.IntersectionPercent(rect1, rect2); } /// /// Gets the rectangle area. /// /// Rectangle. /// Area of the rectangle. public static int Area(this Rectangle rect) { return rect.Width * rect.Height; } /// /// Gets rectangle center. /// /// Rectangle. /// Center of the rectangle. public static Point Center(this Rectangle rect) { return new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2); } /// /// Gets rectangle vertexes in clock-wise order staring from left-upper corner. /// /// Rectangle. /// Vertexes. public static Point[] Vertices(this Rectangle rect) { return new Point[] { new Point(rect.X, rect.Y), //left-upper new Point(rect.Right, rect.Y), //right-upper new Point(rect.Right, rect.Bottom), //right-bottom new Point(rect.X, rect.Bottom) //left-bottom }; } /// /// Gets whether the rectangle has an empty area. It is different than property. /// /// Rectangle. /// True if the rectangle has an empty area. public static bool IsEmptyArea(this Rectangle rect) { return rect.Width == 0 || rect.Height == 0; } /// /// Gets the bounding rectangle of the rectangle collection. /// /// Rectangle collection. /// Bounding rectangle. public static Rectangle BoundingRectangle(this IEnumerable rectangles) { int minX = Int16.MaxValue, minY = Int16.MaxValue, maxX = Int16.MinValue, maxY = Int16.MinValue; foreach (var r in rectangles) { if (r.Left < minX) minX = r.Left; if (r.Top < minY) minY = r.Top; if (r.Right > maxX) maxX = r.Right; if (r.Bottom > maxY) maxY = r.Bottom; } return Rectangle.FromLTRB(minX, minY, maxX, maxY); } } /// /// Defined functions can be used as object extensions. /// Provides extension methods for rectangle structure. /// public static class RectangleFExtensions { /// /// Gets intersection percent of two rectangles. /// /// First rectangle. /// Second rectangle. /// Intersection percent (1 - full intersection, 0 - no intersection). public static float IntersectionPercent(this RectangleF rect1, RectangleF rect2) { float rect1Area = rect1.Width * rect1.Height; float rect2Area = rect2.Width * rect2.Height; RectangleF interesectRect = RectangleF.Intersect(rect1, rect2); float intersectRectArea = interesectRect.Width * interesectRect.Height; float minRectArea = System.Math.Min(rect1Area, rect2Area); return (float)intersectRectArea / minRectArea; } /// /// Gets the rectangle area. /// /// Rectangle. /// Area of the rectangle. public static float Area(this RectangleF rect) { return rect.Width * rect.Height; } /// /// Gets rectangle center. /// /// Rectangle. /// Center of the rectangle. public static PointF Center(this RectangleF rect) { return new PointF(rect.X + rect.Width / 2, rect.Y + rect.Height / 2); } /// /// Gets rectangle vertexes in clock-wise order staring from left-upper corner. /// /// Rectangle. /// Vertexes. public static PointF[] Vertices(this RectangleF rect) { return new PointF[] { new PointF(rect.X, rect.Y), //left-upper new PointF(rect.Right, rect.Y), //right-upper new PointF(rect.Right, rect.Bottom), //right-bottom new PointF(rect.X, rect.Bottom) //left-bottom }; } /// /// Gets whether the rectangle has an empty area. It is different than property. /// /// Rectangle. /// True if the rectangle has an empty area. public static bool IsEmptyArea(this RectangleF rect) { return rect.Width == 0 || rect.Height == 0; } /// /// Gets the bounding rectangle of the rectangle collection. /// /// Rectangle collection. /// Bounding rectangle. public static RectangleF BoundingRectangle(this IEnumerable rectangles) { float minX = Int16.MaxValue, minY = Int16.MaxValue, maxX = Int16.MinValue, maxY = Int16.MinValue; foreach (var r in rectangles) { if (r.Left < minX) minX = r.Left; if (r.Top < minY) minY = r.Top; if (r.Right > maxX) maxX = r.Right; if (r.Bottom > maxY) maxY = r.Bottom; } return RectangleF.FromLTRB(minX, minY, maxX, maxY); } } } ================================================ FILE: Source/Primitives2D/Size/SizeExtensions.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2018 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System.Drawing; namespace DotImaging.Primitives2D { /// /// Defined functions can be used as object extensions. /// Provides size extension methods. /// public static class SizeExtensions { /// /// Gets the size area. /// /// Size. /// Area. public static int Area(this Size size) { return size.Width * size.Height; } /// /// Converts the specified size into the rectangle representation with zero offset. /// /// Size. /// Rectangle with zero offset. public static Rectangle ToRectangle(this Size size) { return new Rectangle(Point.Empty, size); } /// /// Scales (multiplies) the provided size with the specified scale factor. /// /// Size. /// Scale factor. /// Scaled size. public static Size Scale(this Size size, float scale) { return new Size((int)(size.Width * scale), (int)(size.Height * scale)); } } /// /// Defined functions can be used as object extensions. /// Provides size extension methods. /// public static class SizeFExtensions { /// /// Gets the size area. /// /// Size. /// Area. public static float Area(this SizeF size) { return size.Width * size.Height; } /// /// Converts the specified size into the rectangle representation with zero offset. /// /// Size. /// Rectangle with zero offset. public static RectangleF ToRectangleF(this SizeF size) { return new RectangleF(PointF.Empty, size); } /// /// Scales (multiplies) the provided size with the specified scale factor. /// /// Size. /// Scale factor. /// Scaled size. public static Size Scale(this Size size, float scale) { return new Size((int)(size.Width * scale), (int)(size.Height * scale)); } } } ================================================ FILE: Source/UI.Image/.nuSpec/readmeUI.Image.txt ================================================ Portable standalone UI elements invokable as extensions (image display). image show Bgr[,] image = new Bgr[480, 640]; image.SetValue>(Bgr.Red); image.Show(); ================================================ FILE: Source/UI.Image/Base/CvCoreInvoke.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Runtime.InteropServices; using System.Security; using System.Drawing; namespace DotImaging { /// /// Fonts /// public enum FontTypes { /// /// HERSHEY_SIMPLEX /// HERSHEY_SIMPLEX = 0, /// /// HERSHEY_PLAIN /// HERSHEY_PLAIN = 1, /// /// HERSHEY_DUPLEX /// HERSHEY_DUPLEX = 2, /// /// HERSHEY_COMPLEX /// HERSHEY_COMPLEX = 3, /// /// HERSHEY_TRIPLEX /// HERSHEY_TRIPLEX = 4, /// /// HERSHEY_COMPLEX_SMALL /// HERSHEY_COMPLEX_SMALL = 5, /// /// HERSHEY_SCRIPT_SIMPLEX /// HERSHEY_SCRIPT_SIMPLEX = 6, /// /// HERSHEY_SCRIPT_COMPLEX /// HERSHEY_SCRIPT_COMPLEX = 7 } /// /// Managed structure equivalent to CvFont /// [StructLayout(LayoutKind.Sequential)] public struct Font { /// /// For QT /// private IntPtr fontName; /// /// For QT /// private CvScalar color; /// /// Font type /// public FontTypes FontType; /// /// font data and metrics /// private IntPtr ascii; /// /// /// private IntPtr greek; /// /// /// private IntPtr cyrillic; /// /// Horizontal scale. If equal to 1.0f, the characters have the original width depending on the font type. If equal to 0.5f, the characters are of half the original width. /// public float HorizontalScale; /// /// Vertical scale. If equal to 1.0f, the characters have the original height depending on the font type. If equal to 0.5f, the characters are of half the original height. /// public float VerticalScale; /// /// Approximate tangent of the character slope relative to the vertical line. Zero value means a non-italic font, 1.0f means 45 slope, etc. thickness Thickness of lines composing letters outlines. The function cvLine is used for drawing letters. /// public float Shear; /// /// Thickness of the text strokes. /// public int Thickness; /// /// Horizontal interval between letters. /// private float dx; /// /// Type of the strokes. /// private LineTypes LineType; /// /// Create a Font of the specific type, horizontal scale and vertical scale /// /// The type of the font. /// The horizontal scale of the font. /// The vertical scale of the font. /// Font thickness. public Font(FontTypes type, double hscale, double vscale, int thickness = 1) : this() { CvCoreInvoke.cvInitFont(ref this, type, hscale, vscale, 0, thickness, LineTypes.EightConnected); } /// /// Calculates the binding rectangle for the given text string when the font is used /// /// Input string /// y-coordinate of the baseline relatively to the bottom-most text point /// size of the text string. Height of the text does not include the height of character parts that are below the baseline public Size GetTextSize(string text, int baseline) { var size = new Size(); CvCoreInvoke.cvGetTextSize(text, ref this, ref size, ref baseline); return size; } /// /// Hershey duplex font with vertical scale of two. /// public static Font Big = new Font(FontTypes.HERSHEY_DUPLEX, 1, 2); /// /// Hershey duplex font with vertical scale of 0.5. /// public static Font Normal = new Font(FontTypes.HERSHEY_DUPLEX, 1, 0.5f); /// /// Hershey duplex font with vertical scale of 0.25. /// public static Font Small = new Font(FontTypes.HERSHEY_DUPLEX, 1, 0.25f); } /// /// CV's 4 element vector. /// internal struct CvScalar { /// /// First value. /// public double V0; /// /// Second value. /// public double V1; /// /// Third value. /// public double V2; /// /// Fourth value. /// public double V3; } /// /// The type of line for drawing /// internal enum LineTypes { /// /// 8-connected /// EightConnected = 8, /// /// 4-connected /// FourConnected = 4, /// /// Antialias /// Antialiased = 16 } /// /// Internal class for OpenCV highgui library invocation. /// internal static class CvCoreInvoke { public const CallingConvention CvCallingConvention = CallingConvention.Cdecl; public const string OPENCV_CORE_LIBRARY = "opencv_core2412"; #region Base /// /// Clones the provided image. /// /// Image to clone. /// Cloned image. [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern IplImage* cvCloneImage(IplImage* image); /// /// Releases the provided image. /// /// Image to release. [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern void cvReleaseImage(IplImage** image); /// /// Calculates the weighted sum of two arrays. /// /// First input image. /// Weight for the first array elements. /// Second input array of the same size and channel number as src1. /// Weight of the second array elements. /// Scalar added to each sum. /// Destination array. [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern void cvAddWeighted(IplImage* src1, double alpha, IplImage* src2, double beta, double gamma, IplImage* dst); #endregion /// /// Draws the line segment between pt1 and pt2 points in the image. The line is clipped by the image or ROI rectangle. For non-antialiased lines with integer coordinates the 8-connected or 4-connected Bresenham algorithm is used. Thick lines are drawn with rounding endings. Antialiased lines are drawn using Gaussian filtering. /// /// The image /// First point of the line segment /// Second point of the line segment /// Line color /// Line thickness. /// Type of the line: /// 8 (or 0) - 8-connected line. /// 4 - 4-connected line. /// CV_AA - antialiased line. /// /// Number of fractional bits in the point coordinates [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern void cvLine(IplImage* img, Point pt1, Point pt2, CvScalar color, int thickness, LineTypes lineType, int shift); /// /// Draws a single or multiple polygonal curves /// /// Image /// Array of pointers to polylines /// Array of polyline vertex counters /// Number of polyline contours /// /// Indicates whether the polylines must be drawn closed. /// If !=0, the function draws the line from the last vertex of every contour to the first vertex. /// /// Polyline color /// Thickness of the polyline edges /// Type of the line segments, see cvLine description /// Number of fractional bits in the vertex coordinates [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern void cvPolyLine(IplImage* img, [In]IntPtr[] pts, [In]int[] npts, int contours, [MarshalAs(UnmanagedType.Bool)] bool isClosed, CvScalar color, int thickness, LineTypes lineType, int shift); /// /// Draws a rectangle with two opposite corners pt1 and pt2 /// /// Image /// A rectangle vertex /// Opposite rectangle vertex /// Line color /// Thickness of lines that make up the rectangle. Negative values make the function to draw a filled rectangle. /// Type of the line /// Number of fractional bits in the point coordinates [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern void cvRectangle(IplImage* img, Point pt1, Point pt2, CvScalar color, int thickness, LineTypes lineType, int shift); /// /// Draws a rectangle specified by a CvRect structure /// /// /// Image /// The rectangle to be drawn /// Line color /// Thickness of lines that make up the rectangle. Negative values make the function to draw a filled rectangle. /// Type of the line /// Number of fractional bits in the point coordinates [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern void cvRectangleR(IplImage* img, Rectangle rect, CvScalar color, int thickness, LineTypes lineType, int shift); /// /// Draws a simple or filled circle with given center and radius. The circle is clipped by ROI rectangle. /// /// Image where the circle is drawn /// Center of the circle /// Radius of the circle. /// Color of the circle /// Thickness of the circle outline if positive, otherwise indicates that a filled circle has to be drawn /// Type of the circle boundary /// Number of fractional bits in the center coordinates and radius value [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern void cvCircle(IplImage* img, Point center, int radius, CvScalar color, int thickness, LineTypes lineType, int shift); /// /// Draws a simple or thick elliptic arc or fills an ellipse sector. The arc is clipped by ROI rectangle. A piecewise-linear approximation is used for antialiased arcs and thick arcs. All the angles are given in degrees. /// /// Image /// Center of the ellipse /// Length of the ellipse axes /// Rotation angle /// Starting angle of the elliptic arc /// Ending angle of the elliptic arc /// Ellipse color /// Thickness of the ellipse arc /// Type of the ellipse boundary /// Number of fractional bits in the center coordinates and axes' values [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern void cvEllipse(IplImage* img, Point center, Size axes, double angle, double startAngle, double endAngle, CvScalar color, int thickness, LineTypes lineType, int shift); /// /// Draws contour outlines in the image if thickness >=0 or fills area bounded by the contours if thickness<0. /// /// Image where the contours are to be drawn. Like in any other drawing function, the contours are clipped with the ROI /// Pointer to the first contour /// Color of the external contours /// Color of internal contours /// Maximal level for drawn contours. If 0, only contour is drawn. If 1, the contour and all contours after it on the same level are drawn. If 2, all contours after and all contours one level below the contours are drawn, etc. If the value is negative, the function does not draw the contours following after contour but draws child contours of contour up to abs(maxLevel)-1 level. /// Thickness of lines the contours are drawn with. If it is negative the contour interiors are drawn /// Type of the contour segments /// Shift all the point coordinates by the specified value. It is useful in case if the contours retrived in some image ROI and then the ROI offset needs to be taken into account during the rendering. [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern void cvDrawContours(IplImage* img, IntPtr contour, CvScalar externalColor, CvScalar holeColor, int maxLevel, int thickness, LineTypes lineType, Point offset); /// /// Fills convex polygon interior. This function is much faster than The function cvFillPoly and can fill not only the convex polygons but any monotonic polygon, i.e. a polygon whose contour intersects every horizontal line (scan line) twice at the most /// /// Image /// Array of pointers to a single polygon /// Polygon vertex counter /// Polygon color /// Type of the polygon boundaries /// Number of fractional bits in the vertex coordinates [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern void cvFillConvexPoly(IplImage* img, [In] Point[] pts, int npts, CvScalar color, LineTypes lineType, int shift); #region Text /// /// Initializes the font structure that can be passed to text rendering functions /// /// Pointer to the font structure initialized by the function /// Font name identifier. Only a subset of Hershey fonts are supported now /// Horizontal scale. If equal to 1.0f, the characters have the original width depending on the font type. If equal to 0.5f, the characters are of half the original width /// Vertical scale. If equal to 1.0f, the characters have the original height depending on the font type. If equal to 0.5f, the characters are of half the original height /// Approximate tangent of the character slope relative to the vertical line. Zero value means a non-italic font, 1.0f means 45 slope, etc. thickness Thickness of lines composing letters outlines. The function cvLine is used for drawing letters /// Thickness of the text strokes /// Type of the strokes [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern void cvInitFont(ref Font font, FontTypes fontFace, double hscale, double vscale, double shear, int thickness, LineTypes lineType); /// /// Renders the text in the image with the specified font and color. The printed text is clipped by ROI rectangle. Symbols that do not belong to the specified font are replaced with the rectangle symbol. /// /// Input image /// String to print /// Coordinates of the bottom-left corner of the first letter /// Pointer to the font structure /// Text color [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)] public unsafe static extern void cvPutText(IplImage* img, [MarshalAs(UnmanagedType.LPStr)] String text, Point org, ref Font font, CvScalar color); /// /// Calculates the binding rectangle for the given text string when a specified font is used /// /// Input string /// The font structure /// Resultant size of the text string. Height of the text does not include the height of character parts that are below the baseline /// y-coordinate of the baseline relatively to the bottom-most text point [DllImport(OPENCV_CORE_LIBRARY, CallingConvention = CvCallingConvention)] public static extern void cvGetTextSize([MarshalAs(UnmanagedType.LPStr)] String textString, ref Font font, ref Size textSize, ref int baseline); #endregion } } ================================================ FILE: Source/UI.Image/Base/CvInvoke.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Runtime.InteropServices; using System.Security; namespace DotImaging { /// /// OpenCV image load mode. /// internal enum WindowSizing : int { Normal = 0x00000000, AutoSize = 0x00000001 } /// /// Internal class for OpenCV core / highgui library invocation. /// static class CvInvoke { public const CallingConvention CvCallingConvention = CallingConvention.Cdecl; public const string OPENCV_HIGHGUI_LIBRARY = "opencv_highgui2412"; [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public static extern void cvNamedWindow(string name, WindowSizing sizing); [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public static extern void cvShowImage(string name, ref CvMat image); [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public static extern void cvWaitKey(int delay); [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public static extern void cvDestroyAllWindows(); [DllImport(OPENCV_HIGHGUI_LIBRARY, CallingConvention = CvCallingConvention)] public static extern double cvGetWindowProperty(string name, int prop_id); } } ================================================ FILE: Source/UI.Image/Drawing.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2018 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Drawing; using DotImaging.Primitives2D; namespace DotImaging { /// /// Provides extensions for color format conversion to and from CvSclalar. /// internal static class ColorCvScalarConversionExtensions { public static CvScalar ToCvScalar(this Bgr color) { return new CvScalar{ V0 = color.B, V1 = color.G, V2 = color.R, V3 = Byte.MaxValue }; } public static CvScalar ToCvScalar(this Bgra color) { return new CvScalar{ V0 = color.B, V1 = color.G, V2 = color.R, V3 = color.A }; } } /// /// Provides extension drawing methods which operate on color RGB/RGBA images. /// public static class DrawingNativeImage { internal unsafe static void Draw(Image> image, byte opacity, Action drawingAction) { var cvImg = image.AsCvIplImage(); var cvOverlayImPtr = CvCoreInvoke.cvCloneImage(&cvImg); drawingAction(*cvOverlayImPtr); CvCoreInvoke.cvAddWeighted(cvOverlayImPtr, (float)opacity / Byte.MaxValue, &cvImg, 1 - (float)opacity / Byte.MaxValue, 0, &cvImg); CvCoreInvoke.cvReleaseImage(&cvOverlayImPtr); } #region Rectangle /// /// Draws rectangle. /// /// Input image. /// Rectangle. /// Object's color. /// Border thickness (-1 to fill the object). /// Sets alpha channel where 0 is transparent and 255 is full opaque. public unsafe static void DrawRectangle(this Image> image, Rectangle rect, Bgr color, int thickness, byte opacity = Byte.MaxValue) { if (float.IsNaN(rect.X) || float.IsNaN(rect.Y)) return; Draw(image, opacity, cvImg => { CvCoreInvoke.cvRectangleR(&cvImg, rect, color.ToCvScalar(), thickness, LineTypes.EightConnected, 0); }); } #endregion #region Text /// /// Draws text on the provided image. /// /// Input image. /// User text. /// Font. /// Bottom-left point. /// Text color. /// Sets alpha channel where 0 is transparent and 255 is full opaque. public unsafe static void DrawText(this Image> image, string text, Font font, Point botomLeftPoint, Bgr color, byte opacity = Byte.MaxValue) { Draw(image, opacity, cvImg => { CvCoreInvoke.cvPutText(&cvImg, text, botomLeftPoint, ref font, color.ToCvScalar()); }); } #endregion #region Box & Ellipse /// /// Draws Box2D. /// /// Input image. /// Box 2D. /// Object's color. /// Border thickness (-1 to fill the object). /// Sets alpha channel where 0 is transparent and 255 is full opaque. public unsafe static void Draw2DBox(this Image> image, Box2D box, Bgr color, int thickness, byte opacity = Byte.MaxValue) { if (thickness < 1) throw new NotSupportedException("Only positive values are valid!"); var vertices = box.GetVertices(); Draw(image, opacity, cvImg => { for (int i = 0; i < vertices.Length; i++) { int idx2 = (i + 1) % vertices.Length; CvCoreInvoke.cvLine(&cvImg, vertices[i].Round(), vertices[idx2].Round(), color.ToCvScalar(), thickness, LineTypes.EightConnected, 0); } }); } /// /// Draws ellipse. /// /// Input image. /// Ellipse. /// Object's color. /// Border thickness (-1 to fill the object). /// Sets alpha channel where 0 is transparent and 255 is full opaque. public unsafe static void DrawEllipse(this Image> image, Ellipse ellipse, Bgr color, int thickness, byte opacity = Byte.MaxValue) { Draw(image, opacity, cvImg => { CvCoreInvoke.cvEllipse(&cvImg, ellipse.Center.Round(), Size.Round(ellipse.Size), ellipse.Angle, 0, 360, color.ToCvScalar(), thickness, LineTypes.EightConnected, 0); }); } #endregion #region Contour /// /// Draws contour. /// /// Input image. /// Contour points. /// Contour color. /// Contours thickness (it does not support values smaller than 1). /// Sets alpha channel where 0 is transparent and 255 is full opaque. public unsafe static void DrawPolygon(this Image> image, Point[] polygon, Bgr color, int thickness, byte opacity = Byte.MaxValue) { var contourHandle = GCHandle.Alloc(polygon, GCHandleType.Pinned); Draw(image, opacity, cvImg => { //TODO - noncritical: implement with cvContour CvCoreInvoke.cvPolyLine(&cvImg, new IntPtr[] { contourHandle.AddrOfPinnedObject() }, new int[] { polygon.Length }, 1, true, color.ToCvScalar(), thickness, LineTypes.EightConnected, 0); }); contourHandle.Free(); } #endregion #region Circle /// /// Draws circle. /// /// Input image. /// Circle /// Circle color. /// Contours thickness. /// Sets alpha channel where 0 is transparent and 255 is full opaque. public unsafe static void DrawCircle(this Image> image, Circle circle, Bgr color, int thickness, byte opacity = Byte.MaxValue) { Draw(image, opacity, cvImg => { var center = new Point(circle.X, circle.Y); CvCoreInvoke.cvCircle(&cvImg, center, circle.Radius, color.ToCvScalar(), thickness, LineTypes.EightConnected, 0); }); } /// /// Draws circles. /// /// Input image. /// Circles /// Circle color. /// Contours thickness. /// Sets alpha channel where 0 is transparent and 255 is full opaque. public unsafe static void DrawCircles(this Image> image, IEnumerable circles, Bgr color, int thickness, byte opacity = Byte.MaxValue) { Draw(image, opacity, cvImg => { foreach (var circle in circles) { var center = new Point(circle.X, circle.Y); CvCoreInvoke.cvCircle(&cvImg, center, circle.Radius, color.ToCvScalar(), thickness, LineTypes.EightConnected, 0); } }); } #endregion #region Annotations /// /// Draws rectangle with the specified text on top. /// /// Image. /// User specified area to annotate. /// Label. /// Font to use. public static void DrawAnnotation(this Image> image, Rectangle rect, string text, Font font) { const int VERTICAL_OFFSET = 5; image.DrawRectangle(rect, Bgr.Red, 1); var textSize = font.GetTextSize(text, 0); var bottomLeftPt = new Point(rect.X + rect.Width / 2 - textSize.Width / 2, rect.Top - VERTICAL_OFFSET); image.DrawText(text, font, bottomLeftPt, Bgr.Black); } #endregion } /// /// Provides extension drawing methods which operate on color RGB/RGBA images. /// public static class Drawing { unsafe static void Draw(Bgr[,] image, byte opacity, Action drawingAction) { using (var uImg = image.Lock()) DrawingNativeImage.Draw(uImg, opacity, drawingAction); } #region Rectangle /// /// Draws rectangle. /// /// Input image. /// Rectangle. /// Object's color. /// Border thickness (-1 to fill the object). /// Sets alpha channel where 0 is transparent and 255 is full opaque. public unsafe static void DrawRectangle(this Bgr[,] image, Rectangle rect, Bgr color, int thickness, byte opacity = Byte.MaxValue) { if (float.IsNaN(rect.X) || float.IsNaN(rect.Y)) return; Draw(image, opacity, cvImg => { CvCoreInvoke.cvRectangleR(&cvImg, rect, color.ToCvScalar(), thickness, LineTypes.EightConnected, 0); }); } #endregion #region Text /// /// Draws text on the provided image. /// /// Input image. /// User text. /// Font. /// Bottom-left point. /// Text color. /// Sets alpha channel where 0 is transparent and 255 is full opaque. public unsafe static void DrawText(this Bgr[,] image, string text, Font font, Point botomLeftPoint, Bgr color, byte opacity = Byte.MaxValue) { Draw(image, opacity, cvImg => { CvCoreInvoke.cvPutText(&cvImg, text, botomLeftPoint, ref font, color.ToCvScalar()); }); } #endregion #region Box & Ellipse /// /// Draws Box2D. /// /// Input image. /// Box 2D. /// Object's color. /// Border thickness (-1 to fill the object). /// Sets alpha channel where 0 is transparent and 255 is full opaque. public unsafe static void Draw2DBox(this Bgr[,] image, Box2D box, Bgr color, int thickness, byte opacity = Byte.MaxValue) { if (thickness < 1) throw new NotSupportedException("Only positive values are valid!"); var vertices = box.GetVertices(); Draw(image, opacity, cvImg => { for (int i = 0; i < vertices.Length; i++) { int idx2 = (i + 1) % vertices.Length; CvCoreInvoke.cvLine(&cvImg, vertices[i].Round(), vertices[idx2].Round(), color.ToCvScalar(), thickness, LineTypes.EightConnected, 0); } }); } /// /// Draws ellipse. /// /// Input image. /// Ellipse. /// Object's color. /// Border thickness (-1 to fill the object). /// Sets alpha channel where 0 is transparent and 255 is full opaque. public unsafe static void DrawEllipse(this Bgr[,] image, Ellipse ellipse, Bgr color, int thickness, byte opacity = Byte.MaxValue) { Draw(image, opacity, cvImg => { CvCoreInvoke.cvEllipse(&cvImg, ellipse.Center.Round(), Size.Round(ellipse.Size), ellipse.Angle, 0, 360, color.ToCvScalar(), thickness, LineTypes.EightConnected, 0); }); } #endregion #region Contour /// /// Draws contour. /// /// Input image. /// Contour points. /// Contour color. /// Contours thickness (it does not support values smaller than 1). /// Sets alpha channel where 0 is transparent and 255 is full opaque. public unsafe static void DrawPolygon(this Bgr[,] image, Point[] polygon, Bgr color, int thickness, byte opacity = Byte.MaxValue) { var contourHandle = GCHandle.Alloc(polygon, GCHandleType.Pinned); Draw(image, opacity, cvImg => { //TODO - noncritical: implement with cvContour CvCoreInvoke.cvPolyLine(&cvImg, new IntPtr[] { contourHandle.AddrOfPinnedObject() }, new int[] { polygon.Length }, 1, true, color.ToCvScalar(), thickness, LineTypes.EightConnected, 0); }); contourHandle.Free(); } #endregion #region Circle /// /// Draws circle. /// /// Input image. /// Circle /// Circle color. /// Contours thickness. /// Sets alpha channel where 0 is transparent and 255 is full opaque. public unsafe static void DrawCircle(this Bgr[,] image, Circle circle, Bgr color, int thickness, byte opacity = Byte.MaxValue) { Draw(image, opacity, cvImg => { var center = new Point(circle.X, circle.Y); CvCoreInvoke.cvCircle(&cvImg, center, circle.Radius, color.ToCvScalar(), thickness, LineTypes.EightConnected, 0); }); } /// /// Draws circles. /// /// Input image. /// Circles /// Circle color. /// Contours thickness. /// Sets alpha channel where 0 is transparent and 255 is full opaque. public unsafe static void DrawCircles(this Bgr[,] image, IEnumerable circles, Bgr color, int thickness, byte opacity = Byte.MaxValue) { Draw(image, opacity, cvImg => { foreach (var circle in circles) { var center = new Point(circle.X, circle.Y); CvCoreInvoke.cvCircle(&cvImg, center, circle.Radius, color.ToCvScalar(), thickness, LineTypes.EightConnected, 0); } }); } #endregion #region Annotations /// /// Draws rectangle with the specified text on top. /// /// Image. /// User specified area to annotate. /// Label. /// Font to use. public static void DrawAnnotation(this Bgr[,] image, Rectangle rect, string text, Font font) { const int VERTICAL_OFFSET = 5; image.DrawRectangle(rect, Bgr.Red, 1); var textSize = font.GetTextSize(text, 0); var bottomLeftPt = new Point(rect.X + rect.Width / 2 - textSize.Width / 2, rect.Top - VERTICAL_OFFSET); image.DrawText(text, font, bottomLeftPt, Bgr.Black); } #endregion } } ================================================ FILE: Source/UI.Image/ImageUI.cs ================================================ #region Licence and Terms // DotImaging Framework // https://github.com/dajuric/dot-imaging // // Copyright © Darko Jurić, 2014-2019 // darko.juric2@gmail.com // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; namespace DotImaging { /// /// Provides simple standalone UI elements throughout static methods or extensions. /// public static class ImageUI { /// /// Closes all UI controls if displayed. /// public static void CloseAll() { CvInvoke.cvDestroyAllWindows(); } /// /// Displays the specified image in a window and pauses the execution flow. /// /// Image to show. /// Window title (ID). /// True to adjust form to the image size, false otherwise. public static void ShowDialog(this Bgr[,] image, string windowTitle = "Image", bool autoSize = false) { Show(image, windowTitle, autoSize); while (CvInvoke.cvGetWindowProperty(windowTitle, 0) >= 0) CvInvoke.cvWaitKey(5); } /// /// Displays the specified image in a window (non blocking mode). /// /// Image to show. /// Window title (ID). /// True to adjust form to the image size, false otherwise. public static void Show(this Bgr[,] image, string windowTitle = "Image", bool autoSize = false) { CvInvoke.cvNamedWindow(windowTitle, autoSize ? WindowSizing.AutoSize : WindowSizing.Normal); using (var uIm = image.Lock()) { var mat = uIm.AsCvMat(); CvInvoke.cvShowImage(windowTitle, ref mat); } CvInvoke.cvWaitKey(5); } } } ================================================ FILE: Source/UI.Image/UI.Image.csproj ================================================  x64 DotImaging.UI.Image DotImaging true bin\DotImaging.UI.Image.xml true Readme.txt runtimes\win10-x64\%(FileName)%(Extension) Always runtimes/win-x64/native/ runtimes\win10-x64\%(FileName)%(Extension) Always runtimes/ubuntu.16.04-x64/native/ 5.3.0 DotImaging.UI.Image Image preview dialog and drawing. UI, portable-UI, UI-extensions, DotImaging-UI Darko Jurić Darko Jurić https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Licence.txt https://raw.githubusercontent.com/dajuric/dot-imaging/master/Deploy/Logo/logo-small.png https://raw.githubusercontent.com/dajuric/dot-imaging/ https://raw.githubusercontent.com/dajuric/dot-imaging/ true ../../Deploy/NuGet/bin/ Readme.txt