├── .gitignore ├── Kernels ├── DeBayerKernels.cu ├── Kernels.vcxproj ├── RobustnessModell.cu ├── ShiftMinimizerKernels.cu ├── kernel.cu └── opticalFlow.cu ├── LICENSE ├── PEFStudioDX ├── App.config ├── App.xaml ├── App.xaml.cs ├── BasicKernels.cs ├── DeBayerKernels.cs ├── DeBayerKernels.ptx ├── DeBayerKernelsDebug.ptx ├── EnumConverter.cs ├── ExtraCameraProfiles.xml ├── ImagePresenterDX.xaml ├── ImagePresenterDX.xaml.cs ├── ImageStackAlignatorController.cs ├── LUTControl.xaml ├── LUTControl.xaml.cs ├── LUTHost.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Matrix.cs ├── OpticalFlow.cs ├── OpticalFlowKernels.cs ├── PEFStudioDX.csproj ├── PatchTracker.cs ├── PatchTrackingLevel.cs ├── PreAlignment.cs ├── PreAlignmentStore.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── RobustnessModell.ptx ├── RobustnessModellDebug.ptx ├── RobustnessModellKernel.cs ├── ShiftCollection.cs ├── ShiftMinimizerKernels.cs ├── ShiftMinimizerKernels.ptx ├── ShiftMinimizerKernelsDebug.ptx ├── SlimDX.dll ├── TestRawFile.cs ├── kernel.ptx ├── kernelDebug.ptx ├── opticalFlow.ptx ├── opticalFlowDebug.ptx └── packages.config ├── PefFile ├── DNGColorSpace.cs ├── DNGColorSpec.cs ├── DNGFile.cs ├── DNGMatrix.cs ├── DNGOrientation.cs ├── DNGTemperature.cs ├── DNGUtils.cs ├── DNGVector.cs ├── DNGxyCoord.cs ├── ExifEntry.cs ├── ExtraCameraProfiles.cs ├── FileReader.cs ├── GPSDirectoryEntry.cs ├── ImageFileDirectory.cs ├── ImageFileDirectoryEntry.cs ├── Opcode.cs ├── PEFFile.cs ├── PefFile.csproj ├── PentaxMakerNotes.cs ├── PentaxMakerNotesEntry.cs ├── Properties │ └── AssemblyInfo.cs ├── RawFile.cs ├── SaveTiffTag.cs └── TIFFValueTypes.cs ├── README.md ├── TestingGoogleSuperRes.sln └── pictures ├── AdobeCrop.png ├── SuperResCrop.png ├── alpha.gif ├── app1.png ├── app2.png ├── app21.png ├── app3.png ├── app4.png ├── app5.png ├── beta.gif ├── dmd.gif ├── dms.gif ├── edge.gif ├── fraclam1lam2.gif ├── grandCanyon.png ├── lam1.gif ├── lam2.gif ├── newyorkFrame3.png ├── newyorkFrame3Crop1.png ├── newyorkMerged.png ├── newyorkMergedCrop1.png ├── noiseModel.gif ├── overview.png ├── samsung.png ├── sigmamd.gif ├── sigmamdsqrt2.gif ├── sigmams.gif ├── sigmamssqrt2.gif ├── sqrt2.gif ├── superRes.png └── x.gif /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Microsoft Azure ApplicationInsights config file 170 | ApplicationInsights.config 171 | 172 | # Windows Store app package directory 173 | AppPackages/ 174 | BundleArtifacts/ 175 | 176 | # Visual Studio cache files 177 | # files ending in .cache can be ignored 178 | *.[Cc]ache 179 | # but keep track of directories ending in .cache 180 | !*.[Cc]ache/ 181 | 182 | # Others 183 | ClientBin/ 184 | [Ss]tyle[Cc]op.* 185 | ~$* 186 | *~ 187 | *.dbmdl 188 | *.dbproj.schemaview 189 | *.pfx 190 | *.publishsettings 191 | node_modules/ 192 | orleans.codegen.cs 193 | 194 | # RIA/Silverlight projects 195 | Generated_Code/ 196 | 197 | # Backup & report files from converting an old project file 198 | # to a newer Visual Studio version. Backup files are not needed, 199 | # because we have git ;-) 200 | _UpgradeReport_Files/ 201 | Backup*/ 202 | UpgradeLog*.XML 203 | UpgradeLog*.htm 204 | 205 | # SQL Server files 206 | *.mdf 207 | *.ldf 208 | 209 | # Business Intelligence projects 210 | *.rdl.data 211 | *.bim.layout 212 | *.bim_*.settings 213 | 214 | # Microsoft Fakes 215 | FakesAssemblies/ 216 | 217 | # GhostDoc plugin setting file 218 | *.GhostDoc.xml 219 | 220 | # Node.js Tools for Visual Studio 221 | .ntvs_analysis.dat 222 | 223 | # Visual Studio 6 build log 224 | *.plg 225 | 226 | # Visual Studio 6 workspace options file 227 | *.opt 228 | 229 | # Visual Studio LightSwitch build output 230 | **/*.HTMLClient/GeneratedArtifacts 231 | **/*.DesktopClient/GeneratedArtifacts 232 | **/*.DesktopClient/ModelManifest.xml 233 | **/*.Server/GeneratedArtifacts 234 | **/*.Server/ModelManifest.xml 235 | _Pvt_Extensions 236 | 237 | # LightSwitch generated files 238 | GeneratedArtifacts/ 239 | ModelManifest.xml 240 | 241 | # Paket dependency manager 242 | .paket/paket.exe 243 | 244 | # FAKE - F# Make 245 | .fake/ -------------------------------------------------------------------------------- /Kernels/Kernels.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | {80B85EE4-5AE5-4FD5-80ED-274F7E913606} 15 | Kernels 16 | 10.0 17 | 18 | 19 | 20 | Utility 21 | true 22 | MultiByte 23 | v142 24 | 25 | 26 | Utility 27 | false 28 | true 29 | MultiByte 30 | v142 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | true 45 | $(SolutionDir)PEFStudioDX\ 46 | 47 | 48 | $(SolutionDir)PEFStudioDX\ 49 | 50 | 51 | 52 | Level3 53 | Disabled 54 | WIN32;WIN64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 55 | 56 | 57 | true 58 | Console 59 | cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 60 | 61 | 62 | 64 63 | $(OutDir)%(Filename)Debug.ptx 64 | ptx 65 | 66 | 67 | 68 | 69 | Level3 70 | MaxSpeed 71 | true 72 | true 73 | WIN32;WIN64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 74 | 75 | 76 | true 77 | true 78 | true 79 | Console 80 | cudart_static.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 81 | 82 | 83 | 64 84 | $(OutDir)%(Filename).ptx 85 | ptx 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /Kernels/RobustnessModell.cu: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | 20 | #include "cuda_runtime.h" 21 | #include "device_launch_parameters.h" 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | 28 | extern "C" 29 | __global__ void ComputeRobustnessMask( 30 | const float3* __restrict__ rawImgRef, 31 | const float3* __restrict__ rawImgMoved, 32 | float4* __restrict__ robustnessMask, 33 | cudaTextureObject_t texUV, 34 | int imgWidth, 35 | int imgHeight, 36 | int imgPitch, 37 | int maskPitch, 38 | float alpha, 39 | float beta, 40 | float thresholdM) 41 | { 42 | int pxX = blockIdx.x * blockDim.x + threadIdx.x; 43 | int pxY = blockIdx.y * blockDim.y + threadIdx.y; 44 | 45 | extern __shared__ float3 pixelsRef[]; 46 | int sharedOffset = 3 * 3 * (threadIdx.y * blockDim.x + threadIdx.x); 47 | 48 | if (pxX >= imgWidth - 1|| pxY >= imgHeight - 1 || pxX < 1 || pxY < 1) 49 | return; 50 | 51 | float3 meanRef = make_float3(0, 0, 0); 52 | float3 meanMoved = make_float3(0, 0, 0); 53 | float3 stdRef = make_float3(0, 0, 0); 54 | float3 stdMoved = make_float3(0, 0, 0); 55 | float3 dist = make_float3(0, 0, 0); 56 | float3 sigma = make_float3(0, 0, 0); 57 | 58 | float2 shiftf = tex2D(texUV, ((float)pxX + 0.5f) / (float)imgWidth, ((float)pxY + 0.5f) / (float)imgHeight); 59 | float2 maxShift = shiftf; 60 | float2 minShift = shiftf; 61 | 62 | for (int y = -2; y <= 2; y++) 63 | { 64 | for (int x = -2; x <= 2; x++) 65 | { 66 | float2 s = tex2D(texUV, ((float)pxX + x + 0.5f) / (float)imgWidth, ((float)pxY + y + 0.5f) / (float)imgHeight); 67 | maxShift.x = fmaxf(s.x, shiftf.x); 68 | maxShift.y = fmaxf(s.y, shiftf.y); 69 | minShift.x = fminf(s.x, shiftf.x); 70 | minShift.y = fminf(s.y, shiftf.y); 71 | } 72 | } 73 | 74 | int2 shift; 75 | //half resolution image: 76 | shift.x = roundf(shiftf.x * 0.5f); 77 | shift.y = roundf(shiftf.y * 0.5f); 78 | 79 | for (int y = -1; y <= 1; y++) 80 | { 81 | for (int x = -1; x <= 1; x++) 82 | { 83 | float3 p = *(((float3*)((char*)rawImgRef + imgPitch * (pxY + y))) + pxX + x); 84 | pixelsRef[sharedOffset + (y + 1) * 3 + (x + 1)] = p; 85 | 86 | meanRef.x += p.x; 87 | meanRef.y += p.y; 88 | meanRef.z += p.z; 89 | 90 | int ppy = min(max(pxY + shift.y + y, 0), imgHeight - 1); 91 | int ppx = min(max(pxX + shift.x + x, 0), imgWidth - 1); 92 | p = *(((float3*)((char*)rawImgMoved + imgPitch * (ppy))) + ppx); 93 | meanMoved.x += p.x; 94 | meanMoved.y += p.y; 95 | meanMoved.z += p.z; 96 | } 97 | } 98 | meanRef.x /= 9.0f; 99 | meanRef.y /= 9.0f; 100 | meanRef.z /= 9.0f; 101 | meanMoved.x /= 9.0f; 102 | meanMoved.y /= 9.0f; 103 | meanMoved.z /= 9.0f; 104 | 105 | float meandist = fabs(meanRef.x - meanMoved.x) + fabs(meanRef.y - meanMoved.y) + fabs(meanRef.z - meanMoved.z); 106 | meandist /= 3.0f; 107 | maxShift.x *= 0.5f * meandist; 108 | maxShift.y *= 0.5f * meandist; 109 | minShift.x *= 0.5f * meandist; 110 | minShift.y *= 0.5f * meandist; 111 | 112 | float M = sqrtf((maxShift.x - minShift.x) * (maxShift.x - minShift.x) + (maxShift.y - minShift.y) * (maxShift.y - minShift.y)); 113 | 114 | for (int y = -1; y <= 1; y++) 115 | { 116 | for (int x = -1; x <= 1; x++) 117 | { 118 | int p = sharedOffset + (y + 1) * 3 + (x + 1); 119 | stdRef.x += (pixelsRef[p].x - meanRef.x) * (pixelsRef[p].x - meanRef.x); 120 | stdRef.y += (pixelsRef[p].y - meanRef.y) * (pixelsRef[p].y - meanRef.y); 121 | stdRef.z += (pixelsRef[p].z - meanRef.z) * (pixelsRef[p].z - meanRef.z); 122 | } 123 | } 124 | 125 | stdRef.x = sqrtf(stdRef.x / 9.0f); 126 | stdRef.y = sqrtf(stdRef.y / 9.0f); 127 | stdRef.z = sqrtf(stdRef.z / 9.0f); 128 | 129 | float3 sigmaMD; 130 | sigmaMD.x = sqrtf(alpha * meanRef.x + beta); 131 | sigmaMD.y = sqrtf(alpha * meanRef.y + beta) / sqrtf(2.0f); //we have two green pixels averaged --> devide by sqrtf(2); 132 | sigmaMD.z = sqrtf(alpha * meanRef.z + beta); 133 | 134 | dist.x = fabs(meanRef.x - meanMoved.x); 135 | dist.y = fabs(meanRef.y - meanMoved.y); 136 | dist.z = fabs(meanRef.z - meanMoved.z); 137 | 138 | sigma.x = fmaxf(sigmaMD.x, stdRef.x); 139 | sigma.y = fmaxf(sigmaMD.y, stdRef.y); 140 | sigma.z = fmaxf(sigmaMD.z, stdRef.z); 141 | 142 | dist.x = dist.x * (stdRef.x * stdRef.x / (stdRef.x * stdRef.x + sigmaMD.x * sigmaMD.x)); 143 | dist.y = dist.y * (stdRef.y * stdRef.y / (stdRef.y * stdRef.y + sigmaMD.y * sigmaMD.y)); 144 | dist.z = dist.z * (stdRef.z * stdRef.z / (stdRef.z * stdRef.z + sigmaMD.z * sigmaMD.z));/**/ 145 | 146 | float4 mask; 147 | float s = 1.5f; 148 | if (M > thresholdM) 149 | s = 0; 150 | 151 | const float t = 0.12f; 152 | mask.x = fmaxf(fminf(s * exp(-dist.x * dist.x / (sigma.x * sigma.x)) - t, 1.0f), 0.0f); 153 | mask.y = fmaxf(fminf(s * exp(-dist.y * dist.y / (sigma.y * sigma.y)) - t, 1.0f), 0.0f); 154 | mask.z = fmaxf(fminf(s * exp(-dist.z * dist.z / (sigma.z * sigma.z)) - t, 1.0f), 0.0f); 155 | mask.w = M; 156 | 157 | *(((float4*)((char*)robustnessMask + maskPitch * pxY)) + pxX) = mask; 158 | } -------------------------------------------------------------------------------- /Kernels/ShiftMinimizerKernels.cu: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | 20 | #include "cuda_runtime.h" 21 | #include "device_launch_parameters.h" 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | 28 | extern "C" 29 | __global__ void copyShiftMatrix(float* __restrict__ matrices, int tileCount, int imageCount, int shiftCount) 30 | { 31 | int tile = blockIdx.x * blockDim.x + threadIdx.x; 32 | 33 | if (tile >= tileCount) 34 | return; 35 | 36 | //we copy the matrix of first tile to all other tiles... 37 | if (tile == 0) 38 | return; 39 | 40 | int matrixSize = (imageCount - 1) * shiftCount; 41 | 42 | int offset = (matrixSize) * tile; 43 | 44 | for (int elem = 0; elem < matrixSize; elem++) 45 | { 46 | matrices[offset + elem] = matrices[elem]; 47 | } 48 | } 49 | 50 | extern "C" 51 | __global__ void setPointers(float** __restrict__ shiftMatrixArray, float** __restrict__ shiftMatrixSafeArray, float** __restrict__ matrixSquareArray, 52 | float** __restrict__ matrixInvertedArray, float** __restrict__ solvedMatrixArray, 53 | float2**__restrict__ shiftOneToOneArray, float2** __restrict__ shiftMeasuredArray, float2** __restrict__ shiftOptimArray, 54 | float* shiftMatrices, float* shiftSafeMatrices, float* matricesSquared, float* matricesInverted, float* solvedMatrices, 55 | float2* shiftsOneToOne, float2* shiftsMeasured, float2* shiftsOptim, int tileCount, int imageCount, int shiftCount) 56 | { 57 | int tile = blockIdx.x * blockDim.x + threadIdx.x; 58 | 59 | if (tile >= tileCount) 60 | return; 61 | 62 | int n1 = imageCount - 1; 63 | int m = shiftCount; 64 | 65 | int sizeShiftMatrix = n1 * m; 66 | int sizeSquared = n1 * n1; 67 | 68 | shiftMatrixArray[tile] = shiftMatrices + tile * sizeShiftMatrix; 69 | shiftMatrixSafeArray[tile] = shiftSafeMatrices + tile * sizeShiftMatrix; 70 | matrixSquareArray[tile] = matricesSquared + tile * sizeSquared; 71 | matrixInvertedArray[tile] = matricesInverted + tile * sizeSquared; 72 | solvedMatrixArray[tile] = solvedMatrices + tile * sizeShiftMatrix; 73 | shiftOneToOneArray[tile] = shiftsOneToOne + tile * n1; 74 | shiftOptimArray[tile] = shiftsOptim + tile * m; 75 | shiftMeasuredArray[tile] = shiftsMeasured + tile * m; 76 | } 77 | 78 | 79 | 80 | extern "C" 81 | __global__ void checkForOutliers( 82 | float2* __restrict__ measuredShifts, 83 | const float* __restrict__ optimShiftsT, 84 | float* __restrict__ shiftMatrix, 85 | int* __restrict__ status, 86 | int* __restrict__ inversionInfo, 87 | int tileCount, int imageCount, int shiftCount) 88 | { 89 | int tile = blockIdx.x * blockDim.x + threadIdx.x; 90 | 91 | if (tile >= tileCount) 92 | return; 93 | 94 | if (status[tile] < 0) 95 | return; 96 | 97 | if (inversionInfo[tile] != 0) 98 | { 99 | status[tile] = -1; 100 | return; 101 | } 102 | 103 | int n1 = imageCount - 1; 104 | int m = shiftCount; 105 | int offsetMatrix = (n1 * m) * tile; 106 | int offsetAllVec = m * tile; 107 | 108 | 109 | float max = 1; 110 | int idxMax = -1; 111 | 112 | for (int i = 0; i < m; i++) 113 | { 114 | float distx = measuredShifts[offsetAllVec + i].x - optimShiftsT[2*offsetAllVec + i]; 115 | float disty = measuredShifts[offsetAllVec + i].y - optimShiftsT[2*offsetAllVec + i + m]; 116 | 117 | float dist = distx * distx + disty * disty; 118 | if (dist > max) 119 | { 120 | idxMax = i; 121 | max = dist; 122 | } 123 | } 124 | 125 | status[tile] = idxMax; 126 | //success: we found a meaningful minimum 127 | if (idxMax == -1) 128 | { 129 | return; 130 | } 131 | 132 | //remove the largest outlier 133 | measuredShifts[offsetAllVec + idxMax].x = 0; 134 | measuredShifts[offsetAllVec + idxMax].y = 0; 135 | for (int col = 0; col < n1; col++) 136 | { 137 | shiftMatrix[offsetMatrix + idxMax + col * m] = 0; 138 | } 139 | } 140 | 141 | 142 | extern "C" 143 | __global__ void transposeShifts( 144 | float2 * __restrict__ measuredShifts, 145 | const float* __restrict__ measuredShiftsT, 146 | const float* __restrict__ shiftsOneToOneT, 147 | float2* __restrict__ shiftsOneToOne, 148 | int tileCount, int imageCount, int shiftCount) 149 | { 150 | int tile = blockIdx.x * blockDim.x + threadIdx.x; 151 | int i = blockIdx.y * blockDim.y + threadIdx.y; 152 | 153 | if (tile >= tileCount) 154 | return; 155 | 156 | int n1 = imageCount - 1; 157 | int m = shiftCount; 158 | 159 | if (i >= m) 160 | return; 161 | 162 | int offsetAllVec = m * tile; 163 | 164 | float2 shift; 165 | shift.x = measuredShiftsT[2 * offsetAllVec + i]; 166 | shift.y = measuredShiftsT[2 * offsetAllVec + i + m]; 167 | measuredShifts[offsetAllVec + i] = shift; 168 | 169 | if (i >= n1) 170 | return; 171 | int offsetOneToOne = n1 * tile; 172 | float2 temp; 173 | temp.x = shiftsOneToOneT[2 * offsetOneToOne + i]; 174 | temp.y = shiftsOneToOneT[2 * offsetOneToOne + i + n1]; 175 | shiftsOneToOne[offsetOneToOne + i] = temp; 176 | } 177 | 178 | extern "C" 179 | __global__ void getOptimalShifts( 180 | float2 * __restrict__ optimalShifts, 181 | const float2 * __restrict__ bestShifts, 182 | int imageCount, 183 | int tileCountX, 184 | int tileCountY, 185 | int optimalShiftsPitch, 186 | int referenceImage, 187 | int imageToTrack) 188 | { 189 | int tileIdxX = blockIdx.x * blockDim.x + threadIdx.x; 190 | int tileIdxY = blockIdx.y * blockDim.y + threadIdx.y; 191 | 192 | if (tileIdxX >= tileCountX || tileIdxY >= tileCountY) 193 | return; 194 | 195 | int n1 = imageCount - 1; 196 | 197 | const float2* r = &bestShifts[(tileIdxX + tileIdxY * tileCountX) * n1]; 198 | 199 | float2 totalShift = make_float2(0, 0); 200 | if (referenceImage < imageToTrack) 201 | { 202 | for (int i = referenceImage; i < imageToTrack; i++) 203 | { 204 | totalShift.x += r[i].x; 205 | totalShift.y += r[i].y; 206 | } 207 | } 208 | else if(imageToTrack < referenceImage) 209 | { 210 | for (int i = imageToTrack; i < referenceImage; i++) 211 | { 212 | totalShift.x -= r[i].x; 213 | totalShift.y -= r[i].y; 214 | } 215 | } 216 | 217 | *(((float2*)((char*)(optimalShifts) +optimalShiftsPitch * tileIdxY)) + tileIdxX) = totalShift; 218 | } 219 | 220 | 221 | 222 | extern "C" 223 | __global__ void concatenateShifts( 224 | const float2* __restrict__ const* __restrict__ shiftIn, 225 | int* __restrict__ shiftInPitch, 226 | float2* __restrict__ shiftOut, 227 | int shiftCount, 228 | int tileCountX, int tileCountY) 229 | { 230 | int shift = blockIdx.x * blockDim.x + threadIdx.x; 231 | int tileX = blockIdx.y * blockDim.y + threadIdx.y; 232 | int tileY = blockIdx.z * blockDim.z + threadIdx.z; 233 | 234 | if (tileX >= tileCountX || tileY >= tileCountY || shift >= shiftCount) 235 | return; 236 | 237 | const float2* line = (const float2*)((const char*)(shiftIn[shift]) + shiftInPitch[shift] * tileY); 238 | shiftOut[(tileX + tileY * tileCountX) * shiftCount + shift] = line[tileX]; 239 | } 240 | 241 | extern "C" 242 | __global__ void separateShifts( 243 | const float2* __restrict__ shiftIn, 244 | float2* __restrict__ const * __restrict__ shiftOut, 245 | int* __restrict__ shiftOutPitch, 246 | int shiftCount, 247 | int tileCountX, int tileCountY) 248 | { 249 | int shift = blockIdx.x * blockDim.x + threadIdx.x; 250 | int tileX = blockIdx.y * blockDim.y + threadIdx.y; 251 | int tileY = blockIdx.z * blockDim.z + threadIdx.z; 252 | 253 | if (tileX >= tileCountX || tileY >= tileCountY|| shift >= shiftCount) 254 | return; 255 | 256 | float2* line = (float2*)((char*)(shiftOut[shift]) + shiftOutPitch[shift] * tileY); 257 | line[tileX] = shiftIn[(tileX + tileY * tileCountX) * shiftCount + shift]; 258 | } -------------------------------------------------------------------------------- /Kernels/opticalFlow.cu: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | 20 | #include "cuda_runtime.h" 21 | #include "device_launch_parameters.h" 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | extern "C" 28 | __global__ void WarpingKernel(int width, int height, int stride, 29 | cudaTextureObject_t texUV, float* __restrict__ out, cudaTextureObject_t texToWarp) 30 | { 31 | const int ix = threadIdx.x + blockIdx.x * blockDim.x; 32 | const int iy = threadIdx.y + blockIdx.y * blockDim.y; 33 | 34 | if (ix >= width || iy >= height) return; 35 | 36 | float2 shift = tex2D(texUV, ((float)ix + 0.5f) / (float)width, ((float)iy + 0.5f) / (float)height); 37 | 38 | float x = ((float)ix + 0.5f + shift.x) / (float)width; 39 | float y = ((float)iy + 0.5f + shift.y) / (float)height; 40 | 41 | float pixel = tex2D(texToWarp, x, y); 42 | 43 | *(((float*)((char*)out + stride * (iy))) + (ix)) = pixel; 44 | } 45 | 46 | 47 | extern "C" 48 | __global__ void CreateFlowFieldFromTiles( 49 | float2* __restrict__ outImg, 50 | cudaTextureObject_t texObjShiftXY, 51 | int tileSize, 52 | int tileCountX, 53 | int tileCountY, 54 | int imgWidth, 55 | int imgHeight, 56 | int imgPitch, 57 | float2 baseShift, 58 | float baseRotation) 59 | { 60 | int pxX = blockIdx.x * blockDim.x + threadIdx.x; 61 | int pxY = blockIdx.y * blockDim.y + threadIdx.y; 62 | 63 | if (pxX >= imgWidth || pxY >= imgHeight) 64 | return; 65 | 66 | int tileX = pxX / tileSize; 67 | int tileY = pxY / tileSize; 68 | 69 | tileX = min(tileX, tileCountX - 1); 70 | tileY = min(tileY, tileCountY - 1); 71 | 72 | int tileIdx = tileX + tileY * tileCountX; 73 | float2 shift; 74 | shift.x = 0; 75 | shift.y = 0; 76 | 77 | //add base shift and rotation 78 | shift.x = cosf(baseRotation) * -baseShift.x - sinf(baseRotation) * -baseShift.y; 79 | shift.y = sinf(baseRotation) * -baseShift.x + cosf(baseRotation) * -baseShift.y; 80 | 81 | float patchCenterX = pxX - imgWidth / 2; //in pixels 82 | float patchCenterY = pxY - imgHeight / 2; 83 | 84 | shift.x += cosf(baseRotation) * patchCenterX - sinf(baseRotation) * patchCenterY - patchCenterX; 85 | shift.y += sinf(baseRotation) * patchCenterX + cosf(baseRotation) * patchCenterY - patchCenterY; 86 | 87 | 88 | float2 shiftPatch = tex2D(texObjShiftXY, (pxX + 0.5f) / (float)imgWidth, (pxY + 0.5f) / (float)imgHeight); 89 | shift.x += shiftPatch.x; 90 | shift.y += shiftPatch.y; 91 | 92 | *(((float2*)((char*)outImg + imgPitch * pxY)) + pxX) = shift; 93 | } 94 | 95 | 96 | extern "C" 97 | __global__ void ComputeDerivativesKernel(int width, int height, int stride, 98 | float* Ix, float* Iy, float* Iz, 99 | cudaTextureObject_t texSource, 100 | cudaTextureObject_t texTarget) 101 | { 102 | const int ix = threadIdx.x + blockIdx.x * blockDim.x; 103 | const int iy = threadIdx.y + blockIdx.y * blockDim.y; 104 | 105 | 106 | if (ix >= width || iy >= height) return; 107 | 108 | float dx = 1.0f / (float)width; 109 | float dy = 1.0f / (float)height; 110 | 111 | float x = ((float)ix + 0.5f) * dx; 112 | float y = ((float)iy + 0.5f) * dy; 113 | 114 | float t0, t1; 115 | // x derivative 116 | t0 = tex2D(texSource, x + 2.0f * dx, y); 117 | t0 -= tex2D(texSource, x + 1.0f * dx, y) * 8.0f; 118 | t0 += tex2D(texSource, x - 1.0f * dx, y) * 8.0f; 119 | t0 -= tex2D(texSource, x - 2.0f * dx, y); 120 | t0 /= 12.0f; 121 | 122 | t1 = tex2D(texTarget, x + 2.0f * dx, y); 123 | t1 -= tex2D(texTarget, x + 1.0f * dx, y) * 8.0f; 124 | t1 += tex2D(texTarget, x - 1.0f * dx, y) * 8.0f; 125 | t1 -= tex2D(texTarget, x - 2.0f * dx, y); 126 | t1 /= 12.0f; 127 | 128 | *(((float*)((char*)Ix + stride * iy)) + ix) = (t0 + t1) * 0.5f; 129 | 130 | // t derivative 131 | *(((float*)((char*)Iz + stride * iy)) + ix) = tex2D(texSource, x, y) - tex2D(texTarget, x, y); 132 | 133 | // y derivative 134 | t0 = tex2D(texSource, x, y + 2.0f * dy); 135 | t0 -= tex2D(texSource, x, y + 1.0f * dy) * 8.0f; 136 | t0 += tex2D(texSource, x, y - 1.0f * dy) * 8.0f; 137 | t0 -= tex2D(texSource, x, y - 2.0f * dy); 138 | t0 /= 12.0f; 139 | 140 | t1 = tex2D(texTarget, x, y + 2.0f * dy); 141 | t1 -= tex2D(texTarget, x, y + 1.0f * dy) * 8.0f; 142 | t1 += tex2D(texTarget, x, y - 1.0f * dy) * 8.0f; 143 | t1 -= tex2D(texTarget, x, y - 2.0f * dy); 144 | t1 /= 12.0f; 145 | 146 | *(((float*)((char*)Iy + stride * iy)) + ix) = (t0 + t1) * 0.5f; 147 | } 148 | 149 | 150 | extern "C" 151 | __global__ void ComputeDerivatives2Kernel(int width, int height, int stride, 152 | float* Ix, float* Iy, 153 | cudaTextureObject_t tex) 154 | { 155 | const int ix = threadIdx.x + blockIdx.x * blockDim.x; 156 | const int iy = threadIdx.y + blockIdx.y * blockDim.y; 157 | 158 | if (ix >= width || iy >= height) return; 159 | 160 | float dx = 1.0f / (float)width; 161 | float dy = 1.0f / (float)height; 162 | 163 | float x = ((float)ix + 0.5f) * dx; 164 | float y = ((float)iy + 0.5f) * dy; 165 | 166 | float t0, t1; 167 | // x derivative 168 | t0 = tex2D(tex, x + 2.0f * dx, y); 169 | t0 -= tex2D(tex, x + 1.0f * dx, y) * 8.0f; 170 | t0 += tex2D(tex, x - 1.0f * dx, y) * 8.0f; 171 | t0 -= tex2D(tex, x - 2.0f * dx, y); 172 | t0 /= 12.0f; 173 | 174 | *(((float*)((char*)Ix + stride * iy)) + ix) = t0; 175 | 176 | 177 | // y derivative 178 | t0 = tex2D(tex, x, y + 2.0f * dy); 179 | t0 -= tex2D(tex, x, y + 1.0f * dy) * 8.0f; 180 | t0 += tex2D(tex, x, y - 1.0f * dy) * 8.0f; 181 | t0 -= tex2D(tex, x, y - 2.0f * dy); 182 | t0 /= 12.0f; 183 | 184 | *(((float*)((char*)Iy + stride * iy)) + ix) = t0; 185 | } 186 | 187 | 188 | 189 | extern "C" 190 | __global__ void lucasKanadeOptim( 191 | float2 * __restrict__ shifts, 192 | const float* __restrict__ imFx, 193 | const float* __restrict__ imFy, 194 | const float* __restrict__ imFt, 195 | int pitchShift, 196 | int pitchImg, 197 | int width, 198 | int height, 199 | int halfWindowSize, 200 | float minDet) 201 | { 202 | int pxX = blockIdx.x * blockDim.x + threadIdx.x; 203 | int pxY = blockIdx.y * blockDim.y + threadIdx.y; 204 | 205 | if (pxX < halfWindowSize || pxX >= width - halfWindowSize || 206 | pxY < halfWindowSize || pxY >= height - halfWindowSize) 207 | return; 208 | 209 | int windowSize = halfWindowSize * 2 + 1; 210 | float matMul[4]; 211 | float matMulInv[4]; 212 | float UT[4]; 213 | float S[4]; 214 | float V[4]; 215 | 216 | float UV[2]; 217 | 218 | matMul[0] = matMul[1] = matMul[2] = matMul[3] = 0; 219 | for (int y = -halfWindowSize; y <= halfWindowSize; y++) 220 | { 221 | for (int x = -halfWindowSize; x <= halfWindowSize; x++) 222 | { 223 | int globalX = pxX + x; 224 | int globalY = pxY + y; 225 | 226 | float dx = *(((float*)(((char*)imFx) + globalY * pitchImg)) + globalX); 227 | float dy = *(((float*)(((char*)imFy) + globalY * pitchImg)) + globalX); 228 | 229 | matMul[0] += dx * dx; 230 | matMul[1] += dx * dy; 231 | matMul[3] += dy * dy; 232 | } 233 | } 234 | matMul[2] = matMul[1]; 235 | 236 | //matrix pseudo inversion: 237 | float a = matMul[0]; 238 | float b = matMul[1]; 239 | float c = matMul[2]; 240 | float d = matMul[3]; 241 | 242 | float theta = 0.5f * atan2(2.0f * a * c + 2.0f * b * d, a * a + b * b - c * c - d * d); 243 | float ct = cos(theta); 244 | float st = sin(theta); 245 | UT[0] = ct; 246 | UT[2] = -st; //transposed 247 | UT[1] = st; //transposed 248 | UT[3] = ct; 249 | 250 | float S1 = a * a + b * b + c * c + d * d; 251 | float S2 = sqrtf((a * a + b * b - c * c - d * d) * (a * a + b * b - c * c - d * d) + 4 * (a * c + b * d) * (a * c + b * d)); 252 | float sigma1 = sqrt((S1 + S2) / 2); 253 | float sigma2 = sqrt((S1 - S2) / 2); 254 | 255 | float smin = fminf(sigma1, sigma1); 256 | if (smin < minDet) 257 | return; 258 | 259 | 260 | sigma1 = sigma1 != 0 ? 1.0f / sigma1 : 0; 261 | sigma2 = sigma2 != 0 ? 1.0f / sigma2 : 0; 262 | 263 | S[0] = sigma1; 264 | S[1] = 0; 265 | S[2] = 0; 266 | S[3] = sigma2; 267 | 268 | float epsilon = 0.5f * atan2(2.0f * a * b + 2.0f * c * d, a * a - b * b + c * c - d * d); 269 | 270 | float ce = cos(epsilon); 271 | float se = sin(epsilon); 272 | 273 | float s11 = (a * ct + c * st) * ce + (b * ct + d * st) * se; 274 | float s22 = (a * st - c * ct) * se + (-b * st + d * ct) * ce; 275 | 276 | s11 = s11 > 0.0f ? 1.0f : s11 < 0 ? -1.0f : 0.0f; 277 | s22 = s22 > 0.0f ? 1.0f : s22 < 0 ? -1.0f : 0.0f; 278 | 279 | V[0] = s11 * ce; 280 | V[1] = -s22 * se; 281 | V[2] = s11 * se; 282 | V[3] = s22 * ce; 283 | 284 | matMul[0] = S[0] * UT[0] + S[1] * UT[2]; 285 | matMul[1] = S[0] * UT[1] + S[1] * UT[3]; 286 | matMul[2] = S[2] * UT[0] + S[3] * UT[2]; 287 | matMul[3] = S[2] * UT[1] + S[3] * UT[3]; 288 | 289 | matMulInv[0] = V[0] * matMul[0] + V[1] * matMul[2]; 290 | matMulInv[1] = V[0] * matMul[1] + V[1] * matMul[3]; 291 | matMulInv[2] = V[2] * matMul[0] + V[3] * matMul[2]; 292 | matMulInv[3] = V[2] * matMul[1] + V[3] * matMul[3]; 293 | 294 | int ws2 = windowSize * windowSize; 295 | UV[0] = 0; 296 | UV[1] = 0; 297 | 298 | for (int i = 0; i < ws2; i++) 299 | { 300 | int y = i / windowSize; 301 | int x = i - (y * windowSize); 302 | 303 | int globalX = pxX + x - halfWindowSize; 304 | int globalY = pxY + y - halfWindowSize; 305 | 306 | float dx = *(((float*)(((char*)imFx) + globalY * pitchImg)) + globalX); 307 | float dy = *(((float*)(((char*)imFy) + globalY * pitchImg)) + globalX); 308 | 309 | float dt = *(((float*)(((char*)imFt) + globalY * pitchImg)) + globalX); 310 | 311 | UV[0] += (matMulInv[0] * dx + matMulInv[1] * dy) * dt; 312 | UV[1] += (matMulInv[2] * dx + matMulInv[3] * dy) * dt; 313 | } 314 | 315 | UV[0] = isnan(UV[0]) ? 0 : UV[0]; 316 | UV[1] = isnan(UV[1]) ? 0 : UV[1]; 317 | 318 | /*UV[0] = fmaxf(fminf(2.0f, UV[0]), -2.0f); 319 | UV[1] = fmaxf(fminf(2.0f, UV[1]), -2.0f);*/ 320 | 321 | float2 shift = *(((float2*)(((char*)shifts) + pxY * pitchShift)) + pxX); 322 | shift.x += UV[0]; 323 | shift.y += UV[1]; 324 | *(((float2*)((char*)shifts + pxY * pitchShift)) + pxX) = shift; 325 | } 326 | -------------------------------------------------------------------------------- /PEFStudioDX/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /PEFStudioDX/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /PEFStudioDX/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace PEFStudioDX 10 | { 11 | /// 12 | /// Interaktionslogik für "App.xaml" 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PEFStudioDX/DeBayerKernels.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | using ManagedCuda; 25 | using ManagedCuda.BasicTypes; 26 | using ManagedCuda.VectorTypes; 27 | using ManagedCuda.NPP; 28 | 29 | namespace PEFStudioDX 30 | { 31 | public class DeBayerGreenKernel : CudaKernel 32 | { 33 | public DeBayerGreenKernel(CUmodule module, CudaContext ctx) 34 | : base("deBayerGreenKernel", module, ctx) 35 | { 36 | BlockDimensions = new dim3(32, 16, 1); 37 | GridDimensions = new dim3(1, 1, 1); 38 | } 39 | 40 | public float RunSafe(NPPImage_32fC1 imgIn, NPPImage_32fC3 imgOut, float3 blackPoint, float3 scale) 41 | { 42 | //const int width, const int height, const float* __restrict__ imgIn, int strideIn, float3 *outImage, int strideOut, float3 blackPoint, float3 scale 43 | SetComputeSize((uint)imgIn.Width, (uint)imgIn.Height, 1); 44 | return base.Run(imgIn.Width, imgIn.Height, imgIn.DevicePointer, imgIn.Pitch, imgOut.DevicePointer, imgOut.Pitch, blackPoint, scale); 45 | } 46 | 47 | public float RunSafe(CudaDeviceVariable imgIn, CudaDeviceVariable imgOut, int patchSize, float3 blackPoint, float3 scale) 48 | { 49 | SetComputeSize((uint)patchSize, (uint)patchSize, 1); 50 | return base.Run(patchSize, patchSize, imgIn.DevicePointer, patchSize * 4, imgOut.DevicePointer, patchSize * 12, blackPoint, scale); 51 | } 52 | 53 | public PentaxPefFile.RawFile.BayerColor[] BayerPattern 54 | { 55 | set 56 | { 57 | int[] temp = new int[value.Length]; 58 | for (int i = 0; i < value.Length; i++) 59 | { 60 | temp[i] = (int)value[i]; 61 | } 62 | base.SetConstantVariable("c_cfaPattern", temp); 63 | } 64 | } 65 | } 66 | 67 | public class DeBayerRedBlueKernel : CudaKernel 68 | { 69 | public DeBayerRedBlueKernel(CUmodule module, CudaContext ctx) 70 | : base("deBayerRedBlueKernel", module, ctx) 71 | { 72 | BlockDimensions = new dim3(32, 16, 1); 73 | GridDimensions = new dim3(1, 1, 1); 74 | } 75 | 76 | public float RunSafe(NPPImage_32fC1 imgIn, NPPImage_32fC3 imgOut, float3 blackPoint, float3 scale) 77 | { 78 | //const int width, const int height, const float* __restrict__ imgIn, int strideIn, float3 *outImage, int strideOut, float3 blackPoint, float3 scale 79 | SetComputeSize((uint)imgIn.Width, (uint)imgIn.Height, 1); 80 | return base.Run(imgIn.Width, imgIn.Height, imgIn.DevicePointer, imgIn.Pitch, imgOut.DevicePointer, imgOut.Pitch, blackPoint, scale); 81 | } 82 | 83 | public float RunSafe(CudaDeviceVariable imgIn, CudaDeviceVariable imgOut, int patchSize, float3 blackPoint, float3 scale) 84 | { 85 | SetComputeSize((uint)patchSize, (uint)patchSize, 1); 86 | return base.Run(patchSize, patchSize, imgIn.DevicePointer, patchSize * 4, imgOut.DevicePointer, patchSize * 12, blackPoint, scale); 87 | } 88 | 89 | public PentaxPefFile.RawFile.BayerColor[] BayerPattern 90 | { 91 | set 92 | { 93 | int[] temp = new int[value.Length]; 94 | for (int i = 0; i < value.Length; i++) 95 | { 96 | temp[i] = (int)value[i]; 97 | } 98 | base.SetConstantVariable("c_cfaPattern", temp); 99 | } 100 | } 101 | } 102 | 103 | public class DeBayersSubSampleKernel : CudaKernel 104 | { 105 | private const uint BlockSizeX = 16; 106 | private const uint BlockSizeY = 16; 107 | 108 | public DeBayersSubSampleKernel(CudaContext ctx, CUmodule module) 109 | : base("deBayersSubSample3", module, ctx, BlockSizeX, BlockSizeY) 110 | { 111 | //deBayersSubSample(unsigned short* dataIn, float3* imgOut, int bitDepth, int dimX, int dimY, int strideOut) 112 | } 113 | 114 | public float RunSafe(CudaDeviceVariable imgIn, NPPImage_32fC3 imgOut, float maxVal) 115 | { 116 | SetComputeSize((uint)imgOut.WidthRoi, (uint)imgOut.HeightRoi); 117 | return base.Run(imgIn.DevicePointer, imgOut.DevicePointer, maxVal, imgOut.WidthRoi, imgOut.HeightRoi, imgOut.Pitch); 118 | } 119 | 120 | public PentaxPefFile.RawFile.BayerColor[] BayerPattern 121 | { 122 | set 123 | { 124 | int[] temp = new int[value.Length]; 125 | for (int i = 0; i < value.Length; i++) 126 | { 127 | temp[i] = (int)value[i]; 128 | } 129 | base.SetConstantVariable("c_cfaPattern", temp); 130 | } 131 | } 132 | } 133 | 134 | public class AccumulateImagesKernel : CudaKernel 135 | { 136 | private const uint BlockSizeX = 16; 137 | private const uint BlockSizeY = 16; 138 | 139 | public AccumulateImagesKernel(CudaContext ctx, CUmodule module) 140 | : base("accumulateImages", module, ctx, BlockSizeX, BlockSizeY) 141 | { 142 | /* 143 | * accumulateImages( 144 | unsigned short* __restrict__ dataIn, 145 | float3 * __restrict__ imgOut, 146 | float3 * __restrict__ totalWeights, 147 | const float3 * __restrict__ certaintyMask, 148 | const float3* __restrict__ kernelParam, 149 | const float2* __restrict__ shifts, 150 | float maxVal, int dimX, int dimY, int strideOut) 151 | */ 152 | } 153 | 154 | public float RunSafe(CudaDeviceVariable dataIn, NPPImage_32fC3 imgOut, NPPImage_32fC3 totalWeights, NPPImage_32fC4 certaintyMask, NPPImage_32fC3 kernelParam, NPPImage_32fC2 shifts, float3 whiteLevel, float3 blackLevel) 155 | { 156 | SetComputeSize((uint)imgOut.WidthRoi, (uint)imgOut.HeightRoi); 157 | 158 | return base.Run(dataIn.DevicePointer, imgOut.DevicePointerRoi, totalWeights.DevicePointerRoi, 159 | certaintyMask.DevicePointerRoi, kernelParam.DevicePointerRoi, shifts.DevicePointerRoi, 160 | whiteLevel, blackLevel, imgOut.WidthRoi, imgOut.HeightRoi, imgOut.Pitch, certaintyMask.Pitch, shifts.Pitch); 161 | } 162 | 163 | public PentaxPefFile.RawFile.BayerColor[] BayerPattern 164 | { 165 | set 166 | { 167 | int[] temp = new int[value.Length]; 168 | for (int i = 0; i < value.Length; i++) 169 | { 170 | temp[i] = (int)value[i]; 171 | } 172 | base.SetConstantVariable("c_cfaPattern", temp); 173 | } 174 | } 175 | } 176 | 177 | public class AccumulateImagesSuperResKernel : CudaKernel 178 | { 179 | private const uint BlockSizeX = 16; 180 | private const uint BlockSizeY = 16; 181 | 182 | public AccumulateImagesSuperResKernel(CudaContext ctx, CUmodule module) 183 | : base("accumulateImagesSuperRes", module, ctx, BlockSizeX, BlockSizeY) 184 | { 185 | /* 186 | * accumulateImages( 187 | unsigned short* __restrict__ dataIn, 188 | float3 * __restrict__ imgOut, 189 | float3 * __restrict__ totalWeights, 190 | const float3 * __restrict__ certaintyMask, 191 | const float3* __restrict__ kernelParam, 192 | const float2* __restrict__ shifts, 193 | float maxVal, int dimX, int dimY, int strideOut) 194 | */ 195 | } 196 | 197 | public float RunSafe(CudaDeviceVariable dataIn, NPPImage_32fC3 imgOut, NPPImage_32fC3 totalWeights, NPPImage_32fC4 certaintyMask, NPPImage_32fC4 kernelParam, NPPImage_32fC2 shifts, float3 whiteLevel, float3 blackLevel) 198 | { 199 | SetComputeSize((uint)imgOut.WidthRoi, (uint)imgOut.HeightRoi); 200 | 201 | CudaResourceDesc descKernel = new CudaResourceDesc(kernelParam); 202 | CudaTextureDescriptor texDescKernel = new CudaTextureDescriptor(CUAddressMode.Clamp, CUFilterMode.Linear, CUTexRefSetFlags.NormalizedCoordinates); 203 | CudaTexObject texKernel = new CudaTexObject(descKernel, texDescKernel); 204 | 205 | CudaResourceDesc descShift = new CudaResourceDesc(shifts); 206 | CudaTextureDescriptor texDescShift = new CudaTextureDescriptor(CUAddressMode.Mirror, CUFilterMode.Linear, CUTexRefSetFlags.NormalizedCoordinates); 207 | CudaTexObject texShift = new CudaTexObject(descShift, texDescShift); 208 | 209 | float t = base.Run(dataIn.DevicePointer, imgOut.DevicePointerRoi, totalWeights.DevicePointerRoi, 210 | certaintyMask.DevicePointerRoi, texKernel.TexObject, texShift.TexObject, 211 | whiteLevel, blackLevel, imgOut.WidthRoi, imgOut.HeightRoi, imgOut.Pitch, certaintyMask.Pitch, kernelParam.Pitch, shifts.Pitch); 212 | 213 | texShift.Dispose(); 214 | texKernel.Dispose(); 215 | return t; 216 | } 217 | 218 | public PentaxPefFile.RawFile.BayerColor[] BayerPattern 219 | { 220 | set 221 | { 222 | int[] temp = new int[value.Length]; 223 | for (int i = 0; i < value.Length; i++) 224 | { 225 | temp[i] = (int)value[i]; 226 | } 227 | base.SetConstantVariable("c_cfaPattern", temp); 228 | } 229 | } 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /PEFStudioDX/EnumConverter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | using System.Windows.Data; 25 | using System.ComponentModel; 26 | using System.Reflection; 27 | using System.Windows.Markup; 28 | 29 | namespace PEFStudioDX 30 | { 31 | public class EnumDescriptionTypeConverter : EnumConverter 32 | { 33 | public EnumDescriptionTypeConverter(Type type) 34 | : base(type) 35 | { 36 | } 37 | 38 | public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) 39 | { 40 | if (destinationType == typeof(string)) 41 | { 42 | if (value != null) 43 | { 44 | FieldInfo fi = value.GetType().GetField(value.ToString()); 45 | if (fi != null) 46 | { 47 | var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); 48 | return ((attributes.Length > 0) && (!String.IsNullOrEmpty(attributes[0].Description))) ? attributes[0].Description : value.ToString(); 49 | } 50 | } 51 | return string.Empty; 52 | } 53 | return base.ConvertTo(context, culture, value, destinationType); 54 | } 55 | } 56 | public class EnumBindingSourceExtension : MarkupExtension 57 | { 58 | private Type _enumType; 59 | public Type EnumType 60 | { 61 | get { return this._enumType; } 62 | set 63 | { 64 | if (value != this._enumType) 65 | { 66 | if (null != value) 67 | { 68 | Type enumType = Nullable.GetUnderlyingType(value) ?? value; 69 | 70 | if (!enumType.IsEnum) 71 | throw new ArgumentException("Type must be for an Enum."); 72 | } 73 | this._enumType = value; 74 | } 75 | } 76 | } 77 | public EnumBindingSourceExtension() { } 78 | public EnumBindingSourceExtension(Type enumType) 79 | { 80 | this.EnumType = enumType; 81 | } 82 | public override object ProvideValue(IServiceProvider serviceProvider) 83 | { 84 | if (null == this._enumType) 85 | throw new InvalidOperationException("The EnumType must be specified."); 86 | Type actualEnumType = Nullable.GetUnderlyingType(this._enumType) ?? this._enumType; 87 | Array enumValues = Enum.GetValues(actualEnumType); 88 | if (actualEnumType == this._enumType) 89 | return enumValues; 90 | Array tempArray = Array.CreateInstance(actualEnumType, enumValues.Length + 1); 91 | enumValues.CopyTo(tempArray, 1); 92 | return tempArray; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /PEFStudioDX/ExtraCameraProfiles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | RICOH IMAGING COMPANY, LTD. 6 | PENTAX K-3 7 | 8 | 0.9281921387 9 | -0.4597167969 10 | -0.07611083984 11 | -0.3495941162 12 | 0.9834136963 13 | 0.4286651611 14 | -0.02061462402 15 | 0.0431060791 16 | 0.788482666 17 | 18 | 19 | 0.8190460205 20 | -0.2475128174 21 | -0.1096954346 22 | -0.3995361328 23 | 1.230117798 24 | 0.1880645752 25 | -0.1049804688 26 | 0.1840820313 27 | 0.6998596191 28 | 29 | StandardLightA 30 | D65 31 | 32 | 33 | 100 34 | 200 35 | 400 36 | 800 37 | 1600 38 | 3200 39 | 6400 40 | 41 | 42 | 6.66667E-05 43 | 0.0001 44 | 0.000192308 45 | 0.000357143 46 | 0.000714286 47 | 0.001388889 48 | 0.025 49 | 50 | 51 | 0.0 52 | 0.0 53 | 0.0 54 | 0.0 55 | 0.0 56 | 0.0 57 | 0.0 58 | 59 | 60 | 61 | 16 62 | 16 63 | 6016 64 | 4000 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /PEFStudioDX/ImagePresenterDX.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /PEFStudioDX/LUTControl.xaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /PEFStudioDX/LUTHost.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | using System.Windows; 25 | using System.Windows.Input; 26 | using System.Windows.Media; 27 | 28 | namespace PEFStudioDX 29 | { 30 | public class LUTHost : FrameworkElement 31 | { 32 | private readonly VisualCollection _children; 33 | Nullable dragStart = null; 34 | 35 | public LUTHost() 36 | { 37 | _children = new VisualCollection(this); 38 | MouseLeftButtonUp += LUTHost_MouseLeftButtonUp; 39 | MouseLeftButtonDown += LUTHost_MouseLeftButtonDown; 40 | MouseDown += LUTHost_MouseDown; 41 | MouseLeave += LUTHost_MouseLeave; 42 | MouseMove += LUTHost_MouseMove; 43 | } 44 | 45 | private void LUTHost_MouseDown(object sender, MouseButtonEventArgs e) 46 | { 47 | if (e.ChangedButton == MouseButton.Middle && e.ButtonState == MouseButtonState.Pressed) 48 | { 49 | // Retreive the coordinates of the mouse button event. 50 | Point pt = e.GetPosition((UIElement)sender); 51 | 52 | PointCreateOrDeleteEvent?.Invoke(pt.X / ActualWidth, (ActualHeight - pt.Y) / ActualHeight); 53 | } 54 | } 55 | 56 | public delegate void PointSelectedEventHandler(double x, double y); 57 | public event PointSelectedEventHandler PointSelectedEvent; 58 | 59 | public delegate void PointMovedEventHandler(double x, double y); 60 | public event PointMovedEventHandler PointMovedEvent; 61 | 62 | public delegate void PointCreateOrDeleteEventHandler(double x, double y); 63 | public event PointCreateOrDeleteEventHandler PointCreateOrDeleteEvent; 64 | 65 | public delegate void PointReleasedEventHandler(); 66 | public event PointReleasedEventHandler PointReleasedEvent; 67 | 68 | private void LUTHost_MouseMove(object sender, MouseEventArgs e) 69 | { 70 | if (dragStart != null && e.LeftButton == MouseButtonState.Pressed) 71 | { 72 | var element = (UIElement)sender; 73 | var p2 = e.GetPosition(this); 74 | PointMovedEvent?.Invoke(p2.X / ActualWidth, (ActualHeight - p2.Y) / ActualHeight); 75 | } 76 | } 77 | 78 | private void LUTHost_MouseLeave(object sender, MouseEventArgs e) 79 | { 80 | PointReleasedEvent?.Invoke(); 81 | dragStart = null; 82 | this.ReleaseMouseCapture(); 83 | } 84 | 85 | private void LUTHost_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 86 | { 87 | // Retreive the coordinates of the mouse button event. 88 | Point pt = e.GetPosition((UIElement)sender); 89 | 90 | dragStart = pt; 91 | PointSelectedEvent?.Invoke(pt.X / ActualWidth, (ActualHeight - pt.Y) / ActualHeight); 92 | this.CaptureMouse(); 93 | } 94 | 95 | private void LUTHost_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 96 | { 97 | dragStart = null; 98 | PointReleasedEvent?.Invoke(); 99 | this.ReleaseMouseCapture(); 100 | } 101 | 102 | public HitTestResultBehavior MyCallback(HitTestResult result) 103 | { 104 | PointHitTestResult pointHit = result as PointHitTestResult; 105 | if (pointHit != null) 106 | { 107 | Console.WriteLine("Hit: " + pointHit.PointHit.X / ActualWidth + "; " + (ActualHeight - pointHit.PointHit.Y) / ActualHeight); 108 | } 109 | if (result.VisualHit.GetType() == typeof(System.Windows.Media.DrawingVisual)) 110 | { 111 | if (pointHit != null) 112 | { 113 | dragStart = pointHit.PointHit; 114 | } 115 | this.CaptureMouse(); 116 | } 117 | 118 | return HitTestResultBehavior.Stop; 119 | } 120 | 121 | // Provide a required override for the VisualChildrenCount property. 122 | protected override int VisualChildrenCount => _children.Count; 123 | 124 | // Provide a required override for the GetVisualChild method. 125 | protected override Visual GetVisualChild(int index) 126 | { 127 | if (index < 0 || index >= _children.Count) 128 | { 129 | throw new ArgumentOutOfRangeException(); 130 | } 131 | return _children[index]; 132 | } 133 | 134 | public void DrawPoints(SortedList points, Point[] line) 135 | { 136 | _children.Clear(); 137 | 138 | double width = ActualWidth; 139 | double height = ActualHeight; 140 | 141 | 142 | foreach (var point in line) 143 | { 144 | System.Windows.Media.DrawingVisual drawingVisual = new System.Windows.Media.DrawingVisual(); 145 | DrawingContext drawingContext = drawingVisual.RenderOpen(); 146 | double x = point.X * width; 147 | double y = height - point.Y * height; 148 | 149 | drawingContext.DrawEllipse(Brushes.Blue, null, new Point(x, y), 1, 1); 150 | drawingContext.Close(); 151 | _children.Add(drawingVisual); 152 | } 153 | 154 | 155 | foreach (var point in points) 156 | { 157 | System.Windows.Media.DrawingVisual drawingVisual = new System.Windows.Media.DrawingVisual(); 158 | DrawingContext drawingContext = drawingVisual.RenderOpen(); 159 | Pen pen = new Pen(Brushes.AntiqueWhite, 3); 160 | drawingContext.DrawEllipse(Brushes.Transparent, pen, new Point(point.Key * width, height - point.Value * height), 3, 3); 161 | drawingContext.Close(); 162 | _children.Add(drawingVisual); 163 | } 164 | } 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /PEFStudioDX/Matrix.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | 25 | namespace PEFStudioDX 26 | { 27 | class Matrix3x3 28 | { 29 | private double[] data; 30 | private int cols = 3; 31 | private int rows = 3; 32 | 33 | public Matrix3x3() 34 | { 35 | data = new double[9]; 36 | } 37 | 38 | public double this[int row, int col] 39 | { 40 | get { return data[col + row * cols]; } 41 | set { data[col + row * cols] = value; } 42 | } 43 | 44 | public static Matrix3x3 Mul(Matrix3x3 src, Matrix3x3 value) 45 | { 46 | Matrix3x3 res = new Matrix3x3(); 47 | for (int retx = 0; retx < src.rows; retx++) 48 | for (int rety = 0; rety < value.cols; rety++) 49 | { 50 | double val = 0; 51 | for (int i = 0; i < src.cols; i++) 52 | { 53 | val += src[retx, i] * value[i, rety]; 54 | } 55 | res[retx, rety] = val; 56 | } 57 | return res; 58 | } 59 | 60 | public static Matrix3x3 operator *(Matrix3x3 src, Matrix3x3 value) 61 | { 62 | return Matrix3x3.Mul(src, value); 63 | } 64 | public static Matrix3x3 Unit() 65 | { 66 | Matrix3x3 res = new Matrix3x3(); 67 | res[0, 0] = 1; 68 | res[1, 1] = 1; 69 | res[2, 2] = 1; 70 | return res; 71 | } 72 | 73 | public static Matrix3x3 ShiftAffine(double x, double y) 74 | { 75 | Matrix3x3 res = Unit(); 76 | res[0, 2] = x; 77 | res[1, 2] = y; 78 | return res; 79 | } 80 | 81 | public static Matrix3x3 Rotation(double angInDeg) 82 | { 83 | Matrix3x3 res = Unit(); 84 | double s = Math.Sin(angInDeg / 180.0 * Math.PI); 85 | double c = Math.Cos(angInDeg / 180.0 * Math.PI); 86 | res[0, 0] = c; 87 | res[1, 0] = -s; 88 | res[0, 1] = s; 89 | res[1, 1] = c; 90 | return res; 91 | } 92 | 93 | public static Matrix3x3 RotAroundCenter(double angle, double width, double height) 94 | { 95 | Matrix3x3 res = Matrix3x3.ShiftAffine(width / 2.0, height / 2.0); 96 | res = res * Matrix3x3.Rotation(angle); 97 | res = res * Matrix3x3.ShiftAffine(-width / 2.0, -height / 2.0); 98 | return res; 99 | } 100 | 101 | public override string ToString() 102 | { 103 | string res = "{"; 104 | for (int c = 0; c < cols; c++) 105 | { 106 | for (int r = 0; r < rows; r++) 107 | { 108 | res += this[r, c].ToString("0.000"); 109 | if (r < rows - 1) 110 | res += " "; 111 | else 112 | res += "; "; 113 | } 114 | } 115 | res += "}"; 116 | return res; 117 | } 118 | 119 | public double[,] ToAffine() 120 | { 121 | double[,] res = new double[2, 3]; 122 | for (int c = 0; c < cols; c++) 123 | { 124 | for (int r = 0; r < 2; r++) 125 | { 126 | res[r, c] = this[r, c]; 127 | } 128 | } 129 | return res; 130 | } 131 | 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /PEFStudioDX/OpticalFlow.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.IO; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | using ManagedCuda; 25 | using ManagedCuda.BasicTypes; 26 | using ManagedCuda.VectorTypes; 27 | using ManagedCuda.NPP; 28 | 29 | namespace PEFStudioDX 30 | { 31 | public class OpticalFlow 32 | { 33 | NPPImage_32fC1 d_tmp; 34 | NPPImage_32fC1 d_Ix; 35 | NPPImage_32fC1 d_Iy; 36 | NPPImage_32fC1 d_Iz; 37 | 38 | NPPImage_32fC2 d_flow; 39 | CudaDeviceVariable buffer; 40 | CudaDeviceVariable mean; 41 | CudaDeviceVariable std; 42 | CudaDeviceVariable d_filterX; 43 | CudaDeviceVariable d_filterY; 44 | CudaDeviceVariable d_filterT; 45 | 46 | CreateFlowFieldFromTiles createFlowFieldFromTiles; 47 | WarpingKernel warpingKernel; 48 | ComputeDerivativesKernel computeDerivativesKernel; 49 | LukasKanadeKernel lukasKanade; 50 | 51 | public void FreeDeviceMemory() 52 | { 53 | d_tmp.Dispose(); 54 | d_Ix.Dispose(); 55 | d_Iy.Dispose(); 56 | d_Iz.Dispose(); 57 | //d_imageHalf.Dispose(); 58 | 59 | d_flow.Dispose(); 60 | buffer.Dispose(); 61 | mean.Dispose(); 62 | std.Dispose(); 63 | d_filterX.Dispose(); 64 | d_filterY.Dispose(); 65 | d_filterT.Dispose(); 66 | } 67 | 68 | private void DumpFlowField(NPPImage_32fC2 flow, string filename) 69 | { 70 | float2[] f = new float2[flow.Width * flow.Height]; 71 | 72 | flow.CopyToHost(f); 73 | 74 | FileStream fs = File.OpenWrite(filename); 75 | BinaryWriter bw = new BinaryWriter(fs); 76 | 77 | bw.Write(flow.Width); 78 | bw.Write(flow.Height); 79 | 80 | for (int i = 0; i < f.Length; i++) 81 | { 82 | bw.Write(f[i].x); 83 | bw.Write(f[i].y); 84 | } 85 | 86 | bw.Close(); 87 | fs.Close(); 88 | bw.Dispose(); 89 | fs.Dispose(); 90 | } 91 | 92 | private void DumpImage(NPPImage_32fC1 img, string filename) 93 | { 94 | float[] f = new float[img.Width * img.Height]; 95 | 96 | img.CopyToHost(f); 97 | 98 | FileStream fs = File.OpenWrite(filename); 99 | BinaryWriter bw = new BinaryWriter(fs); 100 | 101 | bw.Write(img.Width); 102 | bw.Write(img.Height); 103 | 104 | for (int i = 0; i < f.Length; i++) 105 | { 106 | bw.Write(f[i]); 107 | } 108 | 109 | bw.Close(); 110 | fs.Close(); 111 | bw.Dispose(); 112 | fs.Dispose(); 113 | } 114 | 115 | public OpticalFlow(int width, int height, CudaContext ctx) 116 | { 117 | CUmodule mod = ctx.LoadModulePTX("opticalFlow.ptx"); 118 | 119 | warpingKernel = new WarpingKernel(ctx, mod); 120 | createFlowFieldFromTiles = new CreateFlowFieldFromTiles(ctx, mod); 121 | computeDerivativesKernel = new ComputeDerivativesKernel(ctx, mod); 122 | lukasKanade = new LukasKanadeKernel(ctx, mod); 123 | 124 | d_tmp = new NPPImage_32fC1(width, height); 125 | d_Ix = new NPPImage_32fC1(width, height); 126 | d_Iy = new NPPImage_32fC1(width, height); 127 | d_Iz = new NPPImage_32fC1(width, height); 128 | d_flow = new NPPImage_32fC2(width, height); 129 | 130 | buffer = new CudaDeviceVariable(d_tmp.MeanStdDevGetBufferHostSize() * 3); 131 | mean = new CudaDeviceVariable(1); 132 | std = new CudaDeviceVariable(1); 133 | 134 | 135 | d_filterX = new float[] { -0.25f, 0.25f, -0.25f, 0.25f }; 136 | d_filterY = new float[] { -0.25f, -0.25f, 0.25f, 0.25f }; 137 | d_filterT = new float[] { 0.25f, 0.25f, 0.25f, 0.25f }; 138 | } 139 | 140 | private void Swap(ref NPPImage_32fC2 a, ref NPPImage_32fC2 b) 141 | { 142 | NPPImage_32fC2 temp = a; 143 | a = b; 144 | b = temp; 145 | } 146 | 147 | public void LucasKanade(NPPImage_32fC1 sourceImg, NPPImage_32fC1 targetImg, NPPImage_32fC2 tiledFlow, int tileSize, int tileCountX, int tileCountY, int iterations, float2 baseShift, float baseRotation, float minDet, int windowSize) 148 | { 149 | createFlowFieldFromTiles.RunSafe(tiledFlow, d_flow, baseShift, baseRotation, tileSize, tileCountX, tileCountY); 150 | 151 | for (int iter = 0; iter < iterations; iter++) 152 | { 153 | warpingKernel.RunSafe(sourceImg, d_tmp, d_flow); 154 | NppiPoint p = new NppiPoint(0,0); 155 | d_Ix.Set(0); 156 | d_Iy.Set(0); 157 | d_Iz.Set(0); 158 | 159 | computeDerivativesKernel.RunSafe(d_tmp, targetImg, d_Ix, d_Iy, d_Iz); 160 | lukasKanade.RunSafe(d_flow, d_Ix, d_Iy, d_Iz, minDet, windowSize); 161 | } 162 | warpingKernel.RunSafe(sourceImg, d_tmp, d_flow); 163 | d_tmp.Copy(sourceImg); 164 | } 165 | 166 | public NPPImage_32fC2 LastFlow 167 | { 168 | get { return d_flow; } 169 | } 170 | 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /PEFStudioDX/OpticalFlowKernels.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | using ManagedCuda; 25 | using ManagedCuda.BasicTypes; 26 | using ManagedCuda.VectorTypes; 27 | using ManagedCuda.NPP; 28 | 29 | namespace PEFStudioDX 30 | { 31 | 32 | public class WarpingKernel : CudaKernel 33 | { 34 | const string kernelName = "WarpingKernel"; 35 | public WarpingKernel(CudaContext ctx, CUmodule module) 36 | : base(kernelName, module, ctx) 37 | { 38 | } 39 | 40 | //int width, int height, int stride, 41 | //cudaTextureObject_t texUV, float* __restrict__ out, cudaTextureObject_t texToWarp 42 | public float RunSafe(NPPImage_32fC1 inImg, NPPImage_32fC1 outImg, NPPImage_32fC2 flow) 43 | { 44 | this.BlockDimensions = new dim3(32, 6, 1); 45 | this.SetComputeSize((uint)(outImg.WidthRoi), (uint)(outImg.HeightRoi), 1); 46 | 47 | CudaResourceDesc descImg = new CudaResourceDesc(inImg); 48 | CudaTextureDescriptor texDescImg = new CudaTextureDescriptor(CUAddressMode.Mirror, CUFilterMode.Linear, CUTexRefSetFlags.NormalizedCoordinates); 49 | CudaTexObject texImg = new CudaTexObject(descImg, texDescImg); 50 | 51 | CudaResourceDesc descFlow = new CudaResourceDesc(flow); 52 | CudaTextureDescriptor texDescFlow = new CudaTextureDescriptor(CUAddressMode.Clamp, CUFilterMode.Point, CUTexRefSetFlags.NormalizedCoordinates); 53 | CudaTexObject texFlow = new CudaTexObject(descFlow, texDescFlow); 54 | 55 | return this.Run(outImg.WidthRoi, outImg.HeightRoi, outImg.Pitch, texFlow.TexObject, outImg.DevicePointerRoi, texImg.TexObject); 56 | } 57 | } 58 | public class CreateFlowFieldFromTiles : CudaKernel 59 | { 60 | const string kernelName = "CreateFlowFieldFromTiles"; 61 | public CreateFlowFieldFromTiles(CudaContext ctx, CUmodule module) 62 | : base(kernelName, module, ctx) 63 | { 64 | } 65 | 66 | //float2* __restrict__ outImg, 67 | //cudaTextureObject_t texObjShiftXY, 68 | //int imgWidth, 69 | //int imgHeight, 70 | //int imgPitch 71 | public float RunSafe(NPPImage_32fC2 inFlow, NPPImage_32fC2 outFlow, float2 baseShift, float baseRotation, int tileSize, int tileCountX, int tileCountY) 72 | { 73 | this.BlockDimensions = new dim3(32, 6, 1); 74 | this.SetComputeSize((uint)(outFlow.WidthRoi), (uint)(outFlow.HeightRoi), 1); 75 | 76 | CudaResourceDesc descImg = new CudaResourceDesc(inFlow); 77 | CudaTextureDescriptor texDescImg = new CudaTextureDescriptor(CUAddressMode.Clamp, CUFilterMode.Linear, CUTexRefSetFlags.NormalizedCoordinates); 78 | CudaTexObject texImg = new CudaTexObject(descImg, texDescImg); 79 | 80 | 81 | float t = this.Run(outFlow.DevicePointerRoi, texImg.TexObject, tileSize, tileCountX, tileCountY, outFlow.WidthRoi, outFlow.HeightRoi, outFlow.Pitch, baseShift, baseRotation); 82 | texImg.Dispose(); 83 | return t; 84 | } 85 | } 86 | public class ComputeDerivativesKernel : CudaKernel 87 | { 88 | const string kernelName = "ComputeDerivativesKernel"; 89 | public ComputeDerivativesKernel(CudaContext ctx, CUmodule module) 90 | : base(kernelName, module, ctx) 91 | { 92 | } 93 | 94 | //int width, int height, int stride, 95 | //float* Ix, float* Iy, float* Iz, 96 | //cudaTextureObject_t texSource, 97 | //cudaTextureObject_t texTarget 98 | public float RunSafe(NPPImage_32fC1 imgSource, NPPImage_32fC1 imgTarget, NPPImage_32fC1 Ix, NPPImage_32fC1 Iy, NPPImage_32fC1 Iz) 99 | { 100 | this.BlockDimensions = new dim3(32, 6, 1); 101 | this.SetComputeSize((uint)(imgSource.WidthRoi), (uint)(imgSource.HeightRoi), 1); 102 | 103 | CudaResourceDesc descImgSource = new CudaResourceDesc(imgSource); 104 | CudaTextureDescriptor texDescImgSource = new CudaTextureDescriptor(CUAddressMode.Mirror, CUFilterMode.Linear, CUTexRefSetFlags.NormalizedCoordinates); 105 | CudaTexObject texImgSource = new CudaTexObject(descImgSource, texDescImgSource); 106 | 107 | CudaResourceDesc descImgTarget = new CudaResourceDesc(imgTarget); 108 | CudaTextureDescriptor texDescImgTarget = new CudaTextureDescriptor(CUAddressMode.Mirror, CUFilterMode.Linear, CUTexRefSetFlags.NormalizedCoordinates); 109 | CudaTexObject texImgTarget = new CudaTexObject(descImgTarget, texDescImgTarget); 110 | 111 | 112 | float t = this.Run(Ix.WidthRoi, Ix.HeightRoi, Ix.Pitch, Ix.DevicePointerRoi, Iy.DevicePointerRoi, Iz.DevicePointerRoi, texImgSource.TexObject, texImgTarget.TexObject); 113 | 114 | texImgTarget.Dispose(); 115 | texImgSource.Dispose(); 116 | 117 | return t; 118 | } 119 | } 120 | public class ComputeDerivatives2Kernel : CudaKernel 121 | { 122 | const string kernelName = "ComputeDerivatives2Kernel"; 123 | public ComputeDerivatives2Kernel(CudaContext ctx, CUmodule module) 124 | : base(kernelName, module, ctx) 125 | { 126 | } 127 | 128 | public float RunSafe(NPPImage_32fC1 imgSource, NPPImage_32fC1 Ix, NPPImage_32fC1 Iy) 129 | { 130 | this.BlockDimensions = new dim3(32, 6, 1); 131 | this.SetComputeSize((uint)(imgSource.WidthRoi), (uint)(imgSource.HeightRoi), 1); 132 | 133 | CudaResourceDesc descImgSource = new CudaResourceDesc(imgSource); 134 | CudaTextureDescriptor texDescImgSource = new CudaTextureDescriptor(CUAddressMode.Mirror, CUFilterMode.Linear, CUTexRefSetFlags.NormalizedCoordinates); 135 | CudaTexObject texImgSource = new CudaTexObject(descImgSource, texDescImgSource); 136 | 137 | 138 | float t = this.Run(Ix.WidthRoi, Ix.HeightRoi, Ix.Pitch, Ix.DevicePointerRoi, Iy.DevicePointerRoi, texImgSource.TexObject); 139 | 140 | texImgSource.Dispose(); 141 | 142 | return t; 143 | } 144 | } 145 | 146 | public class LukasKanadeKernel : CudaKernel 147 | { 148 | /*const float4 * __restrict__ temp, 149 | float2 * __restrict__ shifts, 150 | const float* __restrict__ imFx, 151 | const float* __restrict__ imFy, 152 | const float* __restrict__ imFt, 153 | int pitchShift, 154 | int pitchImg, 155 | int pitchTemp, 156 | int width, 157 | int height, 158 | int halfWindowSize 159 | */ 160 | const string kernelName = "lucasKanadeOptim"; 161 | public LukasKanadeKernel(CudaContext ctx, CUmodule module) 162 | : base(kernelName, module, ctx) 163 | { 164 | } 165 | public float RunSafe(NPPImage_32fC2 shifts, NPPImage_32fC1 imFx, NPPImage_32fC1 imFy, NPPImage_32fC1 imFt, float minDet, int windowSize) 166 | { 167 | this.BlockDimensions = new dim3(32, 16, 1); 168 | this.SetComputeSize((uint)(shifts.WidthRoi), (uint)(shifts.HeightRoi), 1); 169 | //this.DynamicSharedMemory = (uint)(5 * windowSize * windowSize) * BlockDimensions.x * BlockDimensions.y * sizeof(float); 170 | 171 | int windowSizeHalf = windowSize / 2; 172 | return this.Run(shifts.DevicePointerRoi, imFx.DevicePointerRoi, imFy.DevicePointerRoi, imFt.DevicePointerRoi, shifts.Pitch, imFx.Pitch, shifts.WidthRoi, shifts.HeightRoi, windowSizeHalf, minDet); 173 | 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /PEFStudioDX/PEFStudioDX.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {DB59DD92-0B30-4A14-B494-29E0FF37E48C} 8 | WinExe 9 | PEFStudioDX 10 | PEFStudioDX 11 | v4.7.2 12 | 512 13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 4 15 | true 16 | true 17 | 18 | 19 | AnyCPU 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | false 28 | 29 | 30 | AnyCPU 31 | pdbonly 32 | true 33 | bin\Release\ 34 | TRACE 35 | prompt 36 | 4 37 | false 38 | 39 | 40 | 41 | ..\packages\ManagedCuda-CUBLAS.10.2.41\lib\net40\CudaBlas.dll 42 | 43 | 44 | ..\packages\ManagedCuda-CUFFT.10.2.41\lib\net40\CudaFFT.dll 45 | 46 | 47 | ..\packages\ManagedCuda-102.10.2.41\lib\net40\ManagedCuda.dll 48 | 49 | 50 | ..\packages\ManagedCuda-NPP.10.2.41\lib\net40\NPP.dll 51 | 52 | 53 | .\SlimDX.dll 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 4.0 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | MSBuild:Compile 74 | Designer 75 | 76 | 77 | 78 | LUTControl.xaml 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | Designer 92 | MSBuild:Compile 93 | 94 | 95 | Designer 96 | MSBuild:Compile 97 | 98 | 99 | MSBuild:Compile 100 | Designer 101 | 102 | 103 | App.xaml 104 | Code 105 | 106 | 107 | 108 | 109 | ImagePresenterDX.xaml 110 | 111 | 112 | 113 | MainWindow.xaml 114 | Code 115 | 116 | 117 | 118 | 119 | 120 | 121 | Code 122 | 123 | 124 | True 125 | True 126 | Resources.resx 127 | 128 | 129 | True 130 | Settings.settings 131 | True 132 | 133 | 134 | ResXFileCodeGenerator 135 | Resources.Designer.cs 136 | 137 | 138 | 139 | SettingsSingleFileGenerator 140 | Settings.Designer.cs 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | {ceb1ffe5-2ba8-48aa-ac87-7c5fb5cc01b4} 149 | PefFile 150 | 151 | 152 | 153 | 154 | Always 155 | 156 | 157 | Always 158 | 159 | 160 | Always 161 | 162 | 163 | Always 164 | 165 | 166 | Always 167 | 168 | 169 | Always 170 | 171 | 172 | Always 173 | 174 | 175 | Always 176 | 177 | 178 | Always 179 | 180 | 181 | Always 182 | 183 | 184 | Always 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /PEFStudioDX/PatchTrackingLevel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | 25 | namespace PEFStudioDX 26 | { 27 | public class PatchTrackingLevel 28 | { 29 | int _resizeLevel; 30 | int _tileSize; 31 | int _maxShift; 32 | 33 | public PatchTrackingLevel() 34 | { 35 | _resizeLevel = 1; 36 | _tileSize = 32; 37 | _maxShift = 2; 38 | } 39 | public PatchTrackingLevel(int aResizeLevel, int aTileSize, int aMaxShift) 40 | { 41 | _resizeLevel = aResizeLevel; 42 | _tileSize = aTileSize; 43 | _maxShift = aMaxShift; 44 | } 45 | 46 | public int ResizeLevel 47 | { 48 | get { return _resizeLevel; } 49 | set { _resizeLevel = value; } 50 | } 51 | 52 | public int TileSize 53 | { 54 | get { return _tileSize; } 55 | set { _tileSize = value; } 56 | } 57 | 58 | public int MaxShift 59 | { 60 | get { return _maxShift; } 61 | set { _maxShift = value; } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /PEFStudioDX/PreAlignmentStore.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | using ManagedCuda.VectorTypes; 25 | 26 | namespace PEFStudioDX 27 | { 28 | public class PreAlignmentStore 29 | { 30 | float2[] _shifts; 31 | float[] _rotations; 32 | int _referenceIndex = -1; 33 | 34 | 35 | 36 | public PreAlignmentStore(double4[] initialShifts) 37 | { 38 | int imageCount = initialShifts.Length; 39 | _shifts = new float2[imageCount]; 40 | _rotations = new float[imageCount]; 41 | 42 | double4[] basicShifts = new double4[initialShifts.Length]; 43 | 44 | for (int i = 1; i < imageCount; i++) 45 | { 46 | double4 shiftToI = initialShifts[i]; 47 | double4 shiftToIMinus1 = initialShifts[i - 1]; 48 | 49 | basicShifts[i - 1] = new double4(shiftToI.x - shiftToIMinus1.x, shiftToI.y - shiftToIMinus1.y, shiftToI.z - shiftToIMinus1.z, 0); 50 | } 51 | int minIndex = -1; 52 | 53 | //Reduce total shift: 54 | double2[] shiftLengthMin = new double2[imageCount - 1]; 55 | 56 | for (int i = 0; i < imageCount - 1; i++) 57 | { 58 | double2 a = new double2(); 59 | for (int j = 0; j < i; j++) 60 | { 61 | a.x -= basicShifts[j].x; 62 | a.y -= basicShifts[j].y; 63 | } 64 | 65 | double2 b = new double2(); 66 | for (int j = i; j < imageCount - 1; j++) 67 | { 68 | b.x += basicShifts[j].x; 69 | b.y += basicShifts[j].y; 70 | } 71 | 72 | shiftLengthMin[i].x = a.x + b.x; 73 | shiftLengthMin[i].y = a.y + b.y; 74 | } 75 | 76 | minIndex = -1; 77 | double minShift = double.MaxValue; 78 | for (int i = 0; i < imageCount - 1; i++) 79 | { 80 | double2 a = shiftLengthMin[i]; 81 | double d = System.Math.Sqrt(a.x * a.x + a.y * a.y); 82 | if (d < minShift) 83 | { 84 | minShift = d; 85 | minIndex = i; 86 | } 87 | } 88 | 89 | for (int i = 0; i < imageCount; i++) 90 | { 91 | double4 a = new double4(); 92 | for (int j = i; j < minIndex; j++) 93 | { 94 | a.x -= basicShifts[j].x; 95 | a.y -= basicShifts[j].y; 96 | a.z -= basicShifts[j].z; 97 | } 98 | 99 | for (int j = minIndex; j < i; j++) 100 | { 101 | a.x += basicShifts[j].x; 102 | a.y += basicShifts[j].y; 103 | a.z += basicShifts[j].z; 104 | } 105 | float2 shift = new float2((float)a.x, (float)a.y); 106 | _shifts[i] = shift; 107 | _rotations[i] = (float)a.z; 108 | } 109 | _referenceIndex = minIndex; 110 | } 111 | 112 | public int ReferenceIndex 113 | { 114 | get { return _referenceIndex; } 115 | set { _referenceIndex = value; } 116 | } 117 | 118 | 119 | public float2 GetShift(int from, int to) 120 | { 121 | return _shifts[to] - _shifts[from]; 122 | } 123 | 124 | public float2 GetShift(int to) 125 | { 126 | if (_referenceIndex < 0) 127 | return new float2(0, 0); 128 | return GetShift(_referenceIndex, to); 129 | } 130 | 131 | public float GetRotation(int from, int to) 132 | { 133 | float angle = _rotations[to] - _rotations[from]; 134 | angle = angle / 180.0f * (float)System.Math.PI; 135 | return angle; 136 | } 137 | 138 | public float GetRotation(int to) 139 | { 140 | if (_referenceIndex < 0) 141 | return 0.0f; 142 | return GetRotation(_referenceIndex, to); 143 | } 144 | 145 | public void Reset() 146 | { 147 | for (int i = 0; i < _rotations.Length; i++) 148 | { 149 | _rotations[i] = 0; 150 | } 151 | for (int i = 0; i < _shifts.Length; i++) 152 | { 153 | _shifts[i] = new float2(0,0); 154 | } 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /PEFStudioDX/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // Allgemeine Informationen über eine Assembly werden über die folgenden 8 | // Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, 9 | // die einer Assembly zugeordnet sind. 10 | [assembly: AssemblyTitle("PEFStudioDX")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("PEFStudioDX")] 15 | [assembly: AssemblyCopyright("Copyright © 2019")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly 20 | // für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von 21 | // COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. 22 | [assembly: ComVisible(false)] 23 | 24 | //Um mit dem Erstellen lokalisierbarer Anwendungen zu beginnen, legen Sie 25 | //ImCodeVerwendeteKultur in der .csproj-Datei 26 | //in einer fest. Wenn Sie in den Quelldateien beispielsweise Deutsch 27 | //(Deutschland) verwenden, legen Sie auf \"de-DE\" fest. Heben Sie dann die Auskommentierung 28 | //des nachstehenden NeutralResourceLanguage-Attributs auf. Aktualisieren Sie "en-US" in der nachstehenden Zeile, 29 | //sodass es mit der UICulture-Einstellung in der Projektdatei übereinstimmt. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //Speicherort der designspezifischen Ressourcenwörterbücher 36 | //(wird verwendet, wenn eine Ressource auf der Seite nicht gefunden wird, 37 | // oder in den Anwendungsressourcen-Wörterbüchern nicht gefunden werden kann.) 38 | ResourceDictionaryLocation.SourceAssembly //Speicherort des generischen Ressourcenwörterbuchs 39 | //(wird verwendet, wenn eine Ressource auf der Seite nicht gefunden wird, 40 | // designspezifischen Ressourcenwörterbuch nicht gefunden werden kann.) 41 | )] 42 | 43 | 44 | // Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: 45 | // 46 | // Hauptversion 47 | // Nebenversion 48 | // Buildnummer 49 | // Revision 50 | // 51 | // Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, 52 | // indem Sie "*" wie unten gezeigt eingeben: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /PEFStudioDX/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // Dieser Code wurde von einem Tool generiert. 4 | // Laufzeitversion: 4.0.30319.42000 5 | // 6 | // Änderungen an dieser Datei können fehlerhaftes Verhalten verursachen und gehen verloren, wenn 7 | // der Code erneut generiert wird. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace PEFStudioDX.Properties 12 | { 13 | 14 | 15 | /// 16 | /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. 17 | /// 18 | // Diese Klasse wurde von der StronglyTypedResourceBuilder-Klasse 19 | // über ein Tool wie ResGen oder Visual Studio automatisch generiert. 20 | // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen 21 | // mit der Option /str erneut aus, oder erstellen Sie Ihr VS-Projekt neu. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PEFStudioDX.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle 56 | /// Ressourcenlookups, die diese stark typisierte Ressourcenklasse verwenden. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /PEFStudioDX/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /PEFStudioDX/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace PEFStudioDX.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /PEFStudioDX/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /PEFStudioDX/RobustnessModellKernel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System.Collections.Generic; 20 | using System.Linq; 21 | using System.Text; 22 | using System.Threading.Tasks; 23 | using ManagedCuda; 24 | using ManagedCuda.BasicTypes; 25 | using ManagedCuda.VectorTypes; 26 | using ManagedCuda.NPP; 27 | 28 | namespace PEFStudioDX 29 | { 30 | public class RobustnessModellKernel : CudaKernel 31 | { 32 | const string kernelName = "ComputeRobustnessMask"; 33 | public RobustnessModellKernel(CudaContext ctx, CUmodule module) 34 | : base(kernelName, module, ctx) 35 | { 36 | } 37 | /* 38 | 39 | const float3* __restrict__ rawImgRef, 40 | const float3* __restrict__ rawImgMoved, 41 | float3* __restrict__ robustnessMask, 42 | cudaTextureObject_t texUV, 43 | int imgWidth, 44 | int imgHeight, 45 | int imgPitch, 46 | float alpha, 47 | float beta) 48 | */ 49 | public float RunSafe(NPPImage_32fC3 rawImgRef, NPPImage_32fC3 rawImgMoved, NPPImage_32fC4 robustnessMask, NPPImage_32fC2 shift, float alpha, float beta, float thresholdM) 50 | { 51 | this.BlockDimensions = new dim3(8, 8, 1); 52 | this.SetComputeSize((uint)(rawImgRef.WidthRoi), (uint)(rawImgRef.HeightRoi), 1); 53 | this.DynamicSharedMemory = BlockDimensions.x * BlockDimensions.y * float3.SizeOf * 3 * 3; 54 | 55 | CudaResourceDesc descShift = new CudaResourceDesc(shift); 56 | CudaTextureDescriptor texDescShift = new CudaTextureDescriptor(CUAddressMode.Mirror, CUFilterMode.Linear, CUTexRefSetFlags.NormalizedCoordinates); 57 | CudaTexObject texShift = new CudaTexObject(descShift, texDescShift); 58 | 59 | 60 | float t = this.Run(rawImgRef.DevicePointerRoi, rawImgMoved.DevicePointerRoi, robustnessMask.DevicePointerRoi, texShift.TexObject, rawImgRef.WidthRoi, 61 | rawImgRef.HeightRoi, rawImgRef.Pitch, robustnessMask.Pitch, alpha, beta, thresholdM); 62 | 63 | texShift.Dispose(); 64 | 65 | return t; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /PEFStudioDX/ShiftMinimizerKernels.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | using ManagedCuda; 25 | using ManagedCuda.BasicTypes; 26 | using ManagedCuda.VectorTypes; 27 | using ManagedCuda.NPP; 28 | 29 | namespace PEFStudioDX 30 | { 31 | public class concatenateShiftsKernel : CudaKernel 32 | { 33 | const string kernelName = "concatenateShifts"; 34 | public concatenateShiftsKernel(CudaContext ctx, CUmodule module) 35 | : base(kernelName, module, ctx) 36 | { 37 | } 38 | 39 | /*shiftIn, 40 | float2* __restrict__ shiftOut, 41 | int shiftCount, 42 | int tileCount 43 | */ 44 | 45 | public float RunSafe(CudaDeviceVariable measuredShifts, CudaDeviceVariable shiftPitch, CudaDeviceVariable shiftOut, int shiftCount, int tileCountX, int tileCountY) 46 | { 47 | this.BlockDimensions = new dim3(8, 8, 4); 48 | this.SetComputeSize((uint)(shiftCount), (uint)(tileCountX), (uint)(tileCountY)); 49 | 50 | return this.Run(measuredShifts.DevicePointer, shiftPitch.DevicePointer, shiftOut.DevicePointer, shiftCount, tileCountX, tileCountY); 51 | } 52 | } 53 | public class separateShiftsKernel : CudaKernel 54 | { 55 | const string kernelName = "separateShifts"; 56 | public separateShiftsKernel(CudaContext ctx, CUmodule module) 57 | : base(kernelName, module, ctx) 58 | { 59 | } 60 | 61 | public float RunSafe(CudaDeviceVariable shiftIn, CudaDeviceVariable measuredShifts, CudaDeviceVariable shiftPitch, int shiftCount, int tileCountX, int tileCountY) 62 | { 63 | this.BlockDimensions = new dim3(8, 8, 4); 64 | this.SetComputeSize((uint)(shiftCount), (uint)(tileCountX), (uint)(tileCountY)); 65 | 66 | return this.Run(shiftIn.DevicePointer, measuredShifts.DevicePointer, shiftPitch.DevicePointer, shiftCount, tileCountX, tileCountY); 67 | } 68 | } 69 | public class getOptimalShiftsKernel : CudaKernel 70 | { 71 | /* 72 | getOptimalShifts( 73 | float2 * __restrict__ optimalShifts, 74 | const float2 * __restrict__ bestShifts, 75 | int imageCount, 76 | int tileCountX, 77 | int tileCountY, 78 | int optimalShiftsPitch, 79 | int referenceImage, 80 | int imageToTrack 81 | */ 82 | 83 | const string kernelName = "getOptimalShifts"; 84 | public getOptimalShiftsKernel(CudaContext ctx, CUmodule module) 85 | : base(kernelName, module, ctx) 86 | { 87 | } 88 | 89 | public float RunSafe(NPPImage_32fC2 optimalShifts, CudaDeviceVariable bestShifts, int imageCount, int referenceImage, int imageToTrack) 90 | { 91 | this.BlockDimensions = new dim3(32, 8, 1); 92 | this.SetComputeSize((uint)(optimalShifts.WidthRoi), (uint)(optimalShifts.HeightRoi), 1); 93 | 94 | return this.Run(optimalShifts.DevicePointer, bestShifts.DevicePointer, imageCount, optimalShifts.WidthRoi, optimalShifts.HeightRoi, optimalShifts.Pitch, referenceImage, imageToTrack); 95 | } 96 | } 97 | 98 | public class copyShiftMatrixKernel : CudaKernel 99 | { 100 | const string kernelName = "copyShiftMatrix"; 101 | public copyShiftMatrixKernel(CudaContext ctx, CUmodule module) 102 | : base(kernelName, module, ctx) 103 | { 104 | } 105 | 106 | //copyShiftMatrix(float* __restrict__ matrices, int tileCount, int imageCount, int shiftCount) 107 | public float RunSafe(CudaDeviceVariable matrices, int tileCount, int imageCount, int shiftCount) 108 | { 109 | this.BlockDimensions = new dim3(128, 1, 1); 110 | this.SetComputeSize((uint)tileCount, 1, 1); 111 | 112 | return this.Run(matrices.DevicePointer, tileCount, imageCount, shiftCount); 113 | } 114 | } 115 | 116 | public class setPointersKernel : CudaKernel 117 | { 118 | const string kernelName = "setPointers"; 119 | public setPointersKernel(CudaContext ctx, CUmodule module) 120 | : base(kernelName, module, ctx) 121 | { 122 | } 123 | 124 | /* 125 | * setPointers(float** __restrict__ shiftMatrixArray, float** __restrict__ matrixSquareArray, 126 | float** __restrict__ matrixInvertedArray, float** __restrict__ solvedMatrixArray, 127 | float2**__restrict__ shiftOneToOneArray, float2** __restrict__ shiftMeasuredArray, float2** __restrict__ shiftOptimArray, 128 | float* shiftMatrices, float* matricesSquared, float* matricesInverted, float* solvedMatrices, 129 | float2* shiftsOneToOne, float2* shiftsMeasured, float2* shiftsOptim, int tileCount, int imageCount) 130 | */ 131 | public float RunSafe(CudaDeviceVariable shiftMatrixArray, CudaDeviceVariable shiftMatrixSafeArray, CudaDeviceVariable matrixSquareArray, 132 | CudaDeviceVariable matrixInvertedArray, CudaDeviceVariable solvedMatrixArray, 133 | CudaDeviceVariable shiftOneToOneArray, CudaDeviceVariable shiftMeasuredArray, CudaDeviceVariable shiftOptimArray, 134 | CudaDeviceVariable shiftMatrices, CudaDeviceVariable shiftSafeMatrices, CudaDeviceVariable matricesSquared, CudaDeviceVariable matricesInverted, CudaDeviceVariable solvedMatrices, 135 | CudaDeviceVariable shiftsOneToOne, CudaDeviceVariable shiftsMeasured, CudaDeviceVariable shiftsOptim, int tileCount, int imageCount, int shiftCount) 136 | { 137 | this.BlockDimensions = new dim3(128, 1, 1); 138 | this.SetComputeSize((uint)tileCount, 1, 1); 139 | 140 | return this.Run(shiftMatrixArray.DevicePointer, shiftMatrixSafeArray.DevicePointer, matrixSquareArray.DevicePointer, 141 | matrixInvertedArray.DevicePointer, solvedMatrixArray.DevicePointer, 142 | shiftOneToOneArray.DevicePointer, shiftMeasuredArray.DevicePointer, shiftOptimArray.DevicePointer, 143 | shiftMatrices.DevicePointer, shiftSafeMatrices.DevicePointer, matricesSquared.DevicePointer, matricesInverted.DevicePointer, solvedMatrices.DevicePointer, 144 | shiftsOneToOne.DevicePointer, shiftsMeasured.DevicePointer, shiftsOptim.DevicePointer, tileCount, imageCount, shiftCount); 145 | } 146 | } 147 | 148 | 149 | public class checkForOutliersKernel : CudaKernel 150 | { 151 | const string kernelName = "checkForOutliers"; 152 | public checkForOutliersKernel(CudaContext ctx, CUmodule module) 153 | : base(kernelName, module, ctx) 154 | { 155 | } 156 | 157 | /* 158 | * checkForOutliers( 159 | float2* __restrict__ measuredShifts, 160 | const float2* __restrict__ optimShifts, 161 | const float* __restrict__ shiftsOneToOneT, 162 | float2* __restrict__ shiftsOneToOne, 163 | float* __restrict__ shiftMatrix, 164 | int* __restrict__ status, 165 | int* __restrict__ inversionInfo, 166 | int tileCount, int imageCount) 167 | */ 168 | public float RunSafe(CudaDeviceVariable measuredShifts, CudaDeviceVariable optimShifts, 169 | CudaDeviceVariable shiftMatrix, CudaDeviceVariable status, 170 | CudaDeviceVariable inversionInfo, int tileCount, int imageCount, int shiftCount) 171 | { 172 | this.BlockDimensions = new dim3(128, 1, 1); 173 | this.SetComputeSize((uint)tileCount, 1, 1); 174 | 175 | return this.Run(measuredShifts.DevicePointer, optimShifts.DevicePointer, 176 | shiftMatrix.DevicePointer, status.DevicePointer, 177 | inversionInfo.DevicePointer, tileCount, imageCount, shiftCount); 178 | } 179 | } 180 | 181 | 182 | public class transposeShiftsKernel : CudaKernel 183 | { 184 | const string kernelName = "transposeShifts"; 185 | public transposeShiftsKernel(CudaContext ctx, CUmodule module) 186 | : base(kernelName, module, ctx) 187 | { 188 | } 189 | 190 | /* 191 | * transposeShifts( 192 | float2 * __restrict__ measuredShifts, 193 | const float* __restrict__ measuredShiftsT, 194 | int tileCount, int imageCount) 195 | */ 196 | public float RunSafe(CudaDeviceVariable measuredShifts, CudaDeviceVariable measuredShiftsT, 197 | CudaDeviceVariable shiftsOneToOneT, CudaDeviceVariable shiftsOneToOne, 198 | int tileCount, int imageCount, int shiftCount) 199 | { 200 | uint m = (uint)((imageCount - 1) * ((float)imageCount / 2.0f)); 201 | this.BlockDimensions = new dim3(32, 8, 1); 202 | this.SetComputeSize((uint)tileCount, m, 1); 203 | 204 | return this.Run(measuredShifts.DevicePointer, measuredShiftsT.DevicePointer, 205 | shiftsOneToOneT.DevicePointer, shiftsOneToOne.DevicePointer, 206 | tileCount, imageCount, shiftCount); 207 | } 208 | } 209 | 210 | } 211 | -------------------------------------------------------------------------------- /PEFStudioDX/SlimDX.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/PEFStudioDX/SlimDX.dll -------------------------------------------------------------------------------- /PEFStudioDX/TestRawFile.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | using ManagedCuda; 25 | using ManagedCuda.BasicTypes; 26 | using ManagedCuda.VectorTypes; 27 | using ManagedCuda.NPP; 28 | 29 | 30 | namespace PEFStudioDX 31 | { 32 | public class TestRawFile : PentaxPefFile.RawFile 33 | { 34 | public TestRawFile(string dummyFile, int size, float preShiftX, float preShiftY, float preRotDeg, float shiftX, float shiftY) 35 | : base(dummyFile) 36 | { 37 | //close the file 38 | Close(); 39 | Random rand = new Random(0); 40 | 41 | mRawImage = new ushort[size, size]; 42 | 43 | float[] temp = new float[size * size]; 44 | NPPImage_32fC1 img1 = new NPPImage_32fC1(size, size); 45 | NPPImage_32fC1 img2 = new NPPImage_32fC1(size, size); 46 | NPPImage_16uC1 img16u = new NPPImage_16uC1(size, size); 47 | 48 | for (int i = 0; i < temp.Length; i++) 49 | { 50 | temp[i] = (float)rand.NextDouble(); 51 | } 52 | 53 | img1.CopyToDevice(temp); 54 | img1.FilterGaussBorder(img2, MaskSize.Size_5_X_5, NppiBorderType.Replicate); 55 | img1.Set(0); 56 | img2.WarpAffine(img1, Matrix3x3.ShiftAffine(-preShiftX, -preShiftY).ToAffine(), InterpolationMode.Cubic); 57 | img2.Set(0); 58 | img1.WarpAffine(img2, Matrix3x3.RotAroundCenter(-preRotDeg, size, size).ToAffine(), InterpolationMode.Cubic); 59 | img1.Set(0); 60 | img2.WarpAffine(img1, Matrix3x3.ShiftAffine(-shiftX, -shiftY).ToAffine(), InterpolationMode.Cubic); 61 | img1.Mul(65535); 62 | img1.Convert(img16u, NppRoundMode.Near); 63 | 64 | img16u.CopyToHost(mRawImage, size * sizeof(ushort)); 65 | 66 | double[] colorMatrix = new double[] { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; 67 | mColorSpec = new PentaxPefFile.DNGColorSpec(colorMatrix, colorMatrix, PentaxPefFile.IFDDNGCalibrationIlluminant.Illuminant.D50, 68 | PentaxPefFile.IFDDNGCalibrationIlluminant.Illuminant.D65, new float[] {1f, 1,1f }); 69 | mOrientation = new PentaxPefFile.DNGOrientation(PentaxPefFile.DNGOrientation.Orientation.Normal); 70 | 71 | mWidth = size; 72 | mHeight = size; 73 | mCropLeft = 0; 74 | mCropTop = 0; 75 | mCroppedWidth = size; 76 | mCroppedHeight = size; 77 | mBitDepth = 16; 78 | mISO = 100; 79 | mBayerPattern = new BayerColor[] { BayerColor.Red, BayerColor.Cyan, BayerColor.Blue }; 80 | mWhiteLevel = new float[] { 65535, 65535, 65535 }; 81 | mBlackLevel = new float[] { 0, 0, 0 }; 82 | mWhiteBalance = new float[] { 1, 1, 1 }; ; 83 | mRollAngle = 0; 84 | mRollAnglePresent = false; 85 | mNoiseModelAlpha = float.Epsilon; 86 | mNoiseModelBeta = 0; 87 | mExposureTime = new PentaxPefFile.Rational(1, 1); 88 | mRecordingDate = DateTime.Now; 89 | mMake = "None"; 90 | mUniqueModelName = "Test file"; 91 | 92 | img1.Dispose(); 93 | img2.Dispose(); 94 | img16u.Dispose(); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /PEFStudioDX/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /PefFile/DNGColorSpace.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | 25 | namespace PentaxPefFile 26 | { 27 | //More or less a 1:1 copy of the DNGColorSpace class in Adobe DNG SDK 28 | //https://www.adobe.com/support/downloads/dng/dng_sdk.html 29 | 30 | public class DNGColorSpace 31 | { 32 | DNGMatrix mToPCS; 33 | DNGMatrix mFromPCS; 34 | 35 | //XYZ with D50 to sRGB with D65 36 | public static DNGColorSpace sRGB50 = new DNGColorSpace(new DNGMatrix3x3(0.4360747, 0.3850649, 0.1430804, 37 | 0.2225045, 0.7168786, 0.0606169, 38 | 0.0139322, 0.0971045, 0.7141733)); 39 | //XYZ and ProPhoto D50 40 | public static DNGColorSpace ProPhoto = new DNGColorSpace(new DNGMatrix3x3(0.7976749, 0.1351917, 0.0313534, 41 | 0.2880402, 0.7118741, 0.0000857, 42 | 0.0000000, 0.0000000, 0.8252100)); 43 | 44 | public DNGColorSpace(DNGMatrix3x3 toPCS) 45 | { 46 | // The matrix values are often rounded, so adjust to 47 | // get them to convert device white exactly to the PCS. 48 | DNGVector W1 = toPCS * new DNGVector3(1.0, 1.0, 1.0); 49 | DNGVector W2 = DNGxyCoord.PCStoXYZ; 50 | 51 | double s0 = W2[0] / W1[0]; 52 | double s1 = W2[1] / W1[1]; 53 | double s2 = W2[2] / W1[2]; 54 | 55 | DNGMatrix3x3 S = new DNGMatrix3x3(s0, 0, 0, 56 | 0, s1, 0, 57 | 0, 0, s2); 58 | 59 | mToPCS = S * toPCS; 60 | 61 | // Find reverse matrix. 62 | mFromPCS = mToPCS.Invert(); 63 | } 64 | 65 | public DNGMatrix ToPCS 66 | { 67 | get { return mToPCS; } 68 | } 69 | 70 | public DNGMatrix FromPCS 71 | { 72 | get { return mFromPCS; } 73 | } 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /PefFile/DNGOrientation.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | 25 | namespace PentaxPefFile 26 | { 27 | /// 28 | /// Same as DNG SDK, this is more human readable than TIFF spec. 29 | /// https://www.adobe.com/support/downloads/dng/dng_sdk.html 30 | /// 31 | public class DNGOrientation 32 | { 33 | public enum Orientation 34 | { 35 | Normal = 0, 36 | Rotate90CW = 1, 37 | Rotate180 = 2, 38 | Rotate90CCW = 3, 39 | Mirror = 4, 40 | Mirror90CW = 5, 41 | Mirror180 = 6, 42 | Mirror90CCW = 7, 43 | Unknown = 8 44 | } 45 | 46 | private Orientation _value; 47 | 48 | public DNGOrientation(Orientation aValue) 49 | { 50 | _value = aValue; 51 | } 52 | 53 | public DNGOrientation(ushort tiffOrientation) 54 | { 55 | switch (tiffOrientation) 56 | { 57 | case 1: 58 | _value = Orientation.Normal; 59 | break; 60 | case 2: 61 | _value = Orientation.Mirror; 62 | break; 63 | case 3: 64 | _value = Orientation.Rotate180; 65 | break; 66 | case 4: 67 | _value = Orientation.Mirror180; 68 | break; 69 | case 5: 70 | _value = Orientation.Mirror90CCW; 71 | break; 72 | case 6: 73 | _value = Orientation.Rotate90CW; 74 | break; 75 | case 7: 76 | _value = Orientation.Mirror90CW; 77 | break; 78 | case 8: 79 | _value = Orientation.Rotate90CCW; 80 | break; 81 | case 9: 82 | _value = Orientation.Unknown; 83 | break; 84 | default: 85 | _value = Orientation.Normal; 86 | break; 87 | } 88 | } 89 | 90 | public Orientation Value 91 | { 92 | get { return _value; } 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /PefFile/DNGTemperature.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | 25 | namespace PentaxPefFile 26 | { 27 | //More or less a 1:1 copy of the dng_temperature class in Adobe DNG SDK 28 | //https://www.adobe.com/support/downloads/dng/dng_sdk.html 29 | 30 | public class DNGTemperature 31 | { 32 | const double kTintScale = -3000.0; 33 | struct ruvt 34 | { 35 | public double r; 36 | public double u; 37 | public double v; 38 | public double t; 39 | 40 | public ruvt(double aR, double aU, double aV, double aT) 41 | { 42 | r = aR; 43 | u = aU; 44 | v = aV; 45 | t = aT; 46 | } 47 | }; 48 | 49 | static ruvt[] kTempTable = new ruvt[] 50 | { 51 | new ruvt( 0, 0.18006, 0.26352, -0.24341 ), 52 | new ruvt( 10, 0.18066, 0.26589, -0.25479 ), 53 | new ruvt( 20, 0.18133, 0.26846, -0.26876 ), 54 | new ruvt( 30, 0.18208, 0.27119, -0.28539 ), 55 | new ruvt( 40, 0.18293, 0.27407, -0.30470 ), 56 | new ruvt( 50, 0.18388, 0.27709, -0.32675 ), 57 | new ruvt( 60, 0.18494, 0.28021, -0.35156 ), 58 | new ruvt( 70, 0.18611, 0.28342, -0.37915 ), 59 | new ruvt( 80, 0.18740, 0.28668, -0.40955 ), 60 | new ruvt( 90, 0.18880, 0.28997, -0.44278 ), 61 | new ruvt( 100, 0.19032, 0.29326, -0.47888 ), 62 | new ruvt( 125, 0.19462, 0.30141, -0.58204 ), 63 | new ruvt( 150, 0.19962, 0.30921, -0.70471 ), 64 | new ruvt( 175, 0.20525, 0.31647, -0.84901 ), 65 | new ruvt( 200, 0.21142, 0.32312, -1.0182 ), 66 | new ruvt( 225, 0.21807, 0.32909, -1.2168 ), 67 | new ruvt( 250, 0.22511, 0.33439, -1.4512 ), 68 | new ruvt( 275, 0.23247, 0.33904, -1.7298 ), 69 | new ruvt( 300, 0.24010, 0.34308, -2.0637 ), 70 | new ruvt( 325, 0.24702, 0.34655, -2.4681 ), 71 | new ruvt( 350, 0.25591, 0.34951, -2.9641 ), 72 | new ruvt( 375, 0.26400, 0.35200, -3.5814 ), 73 | new ruvt( 400, 0.27218, 0.35407, -4.3633 ), 74 | new ruvt( 425, 0.28039, 0.35577, -5.3762 ), 75 | new ruvt( 450, 0.28863, 0.35714, -6.7262 ), 76 | new ruvt( 475, 0.29685, 0.35823, -8.5955 ), 77 | new ruvt( 500, 0.30505, 0.35907, -11.324 ), 78 | new ruvt( 525, 0.31320, 0.35968, -15.628 ), 79 | new ruvt( 550, 0.32129, 0.36011, -23.325 ), 80 | new ruvt( 575, 0.32931, 0.36038, -40.770 ), 81 | new ruvt( 600, 0.33724, 0.36051, -116.45 ) 82 | }; 83 | 84 | double _temperature; 85 | double _tint; 86 | 87 | public DNGTemperature() 88 | { 89 | } 90 | 91 | public DNGTemperature(double aTemperature, double aTint) 92 | { 93 | _temperature = aTemperature; 94 | _tint = aTint; 95 | } 96 | 97 | public DNGTemperature(DNGxyCoord xy) 98 | { 99 | xyCoord = xy; 100 | } 101 | 102 | public double Temperature 103 | { 104 | get { return _temperature; } 105 | set { _temperature = value; } 106 | } 107 | 108 | public double Tint 109 | { 110 | get { return _tint; } 111 | set { _tint = value; } 112 | } 113 | 114 | public DNGxyCoord xyCoord 115 | { 116 | get 117 | { 118 | DNGxyCoord result = new DNGxyCoord(); 119 | 120 | // Find inverse temperature to use as index. 121 | double r = 1.0E6 / _temperature; 122 | 123 | // Convert tint to offset is uv space. 124 | double offset = _tint * (1.0 / kTintScale); 125 | 126 | // Search for line pair containing coordinate. 127 | for (uint index = 0; index <= 29; index++) 128 | { 129 | if (r < kTempTable[index + 1].r || index == 29) 130 | { 131 | // Find relative weight of first line. 132 | double f = (kTempTable[index + 1].r - r) / 133 | (kTempTable[index + 1].r - kTempTable[index].r); 134 | 135 | // Interpolate the black body coordinates. 136 | double u = kTempTable[index].u * f + 137 | kTempTable[index + 1].u * (1.0 - f); 138 | 139 | double v = kTempTable[index].v * f + 140 | kTempTable[index + 1].v * (1.0 - f); 141 | 142 | // Find vectors along slope for each line. 143 | double uu1 = 1.0; 144 | double vv1 = kTempTable[index].t; 145 | 146 | double uu2 = 1.0; 147 | double vv2 = kTempTable[index + 1].t; 148 | 149 | double len1 = Math.Sqrt(1.0 + vv1 * vv1); 150 | double len2 = Math.Sqrt(1.0 + vv2 * vv2); 151 | 152 | uu1 /= len1; 153 | vv1 /= len1; 154 | 155 | uu2 /= len2; 156 | vv2 /= len2; 157 | 158 | // Find vector from black body point. 159 | double uu3 = uu1 * f + uu2 * (1.0 - f); 160 | double vv3 = vv1 * f + vv2 * (1.0 - f); 161 | 162 | double len3 = Math.Sqrt(uu3 * uu3 + vv3 * vv3); 163 | 164 | uu3 /= len3; 165 | vv3 /= len3; 166 | 167 | // Adjust coordinate along this vector. 168 | u += uu3 * offset; 169 | v += vv3 * offset; 170 | 171 | // Convert to xy coordinates. 172 | result.X = 1.5 * u / (u - 4.0 * v + 2.0); 173 | result.Y = v / (u - 4.0 * v + 2.0); 174 | 175 | break; 176 | } 177 | } 178 | 179 | return result; 180 | } 181 | 182 | set 183 | { 184 | // Convert to uv space. 185 | double u = 2.0 * value.X / (1.5 - value.X + 6.0 * value.Y); 186 | double v = 3.0 * value.Y / (1.5 - value.X + 6.0 * value.Y); 187 | 188 | // Search for line pair coordinate is between. 189 | double last_dt = 0.0; 190 | double last_dv = 0.0; 191 | double last_du = 0.0; 192 | 193 | for (uint index = 1; index <= 30; index++) 194 | { 195 | // Convert slope to delta-u and delta-v, with length 1. 196 | double du = 1.0; 197 | double dv = kTempTable[index].t; 198 | 199 | double len = Math.Sqrt(1.0 + dv * dv); 200 | du /= len; 201 | dv /= len; 202 | 203 | // Find delta from black body point to test coordinate. 204 | double uu = u - kTempTable[index].u; 205 | double vv = v - kTempTable[index].v; 206 | 207 | // Find distance above or below line. 208 | double dt = -uu * dv + vv * du; 209 | 210 | // If below line, we have found line pair. 211 | if (dt <= 0.0 || index == 30) 212 | { 213 | // Find fractional weight of two lines. 214 | if (dt > 0.0) 215 | dt = 0.0; 216 | 217 | dt = -dt; 218 | 219 | double f; 220 | 221 | if (index == 1) 222 | { 223 | f = 0.0; 224 | } 225 | else 226 | { 227 | f = dt / (last_dt + dt); 228 | } 229 | 230 | // Interpolate the temperature. 231 | _temperature = 1.0E6 / (kTempTable[index - 1].r * f + 232 | kTempTable[index].r * (1.0 - f)); 233 | 234 | // Find delta from black body point to test coordinate. 235 | uu = u - (kTempTable[index - 1].u * f + 236 | kTempTable[index].u * (1.0 - f)); 237 | 238 | vv = v - (kTempTable[index - 1].v * f + 239 | kTempTable[index].v * (1.0 - f)); 240 | 241 | // Interpolate vectors along slope. 242 | du = du * (1.0 - f) + last_du * f; 243 | dv = dv * (1.0 - f) + last_dv * f; 244 | 245 | len = Math.Sqrt(du * du + dv * dv); 246 | 247 | du /= len; 248 | dv /= len; 249 | 250 | // Find distance along slope. 251 | _tint = (uu * du + vv * dv) * kTintScale; 252 | break; 253 | } 254 | 255 | // Try next line pair. 256 | last_dt = dt; 257 | last_du = du; 258 | last_dv = dv; 259 | } 260 | } 261 | } 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /PefFile/DNGUtils.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | 25 | namespace PentaxPefFile 26 | { 27 | public static class DNGUtils 28 | { 29 | public static double Pin(double min, double x, double max) 30 | { 31 | return Math.Max(min, Math.Min(x, max)); 32 | } 33 | 34 | public static double Pin(double x) 35 | { 36 | return Pin(0.0, x, 1.0); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /PefFile/DNGxyCoord.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | 25 | namespace PentaxPefFile 26 | { 27 | //More or less a 1:1 copy of the DNGxyCoord class in Adobe DNG SDK 28 | //https://www.adobe.com/support/downloads/dng/dng_sdk.html 29 | 30 | public class DNGxyCoord 31 | { 32 | double x; 33 | double y; 34 | 35 | public DNGxyCoord() 36 | { 37 | } 38 | 39 | public DNGxyCoord(double xx, double yy) 40 | { 41 | x = xx; 42 | y = yy; 43 | } 44 | 45 | public DNGxyCoord(DNGxyCoord a) 46 | { 47 | x = a.x; 48 | y = a.y; 49 | } 50 | 51 | public double X 52 | { 53 | get { return x; } 54 | set { x = value; } 55 | } 56 | 57 | public double Y 58 | { 59 | get { return y; } 60 | set { y = value; } 61 | } 62 | 63 | public void Clear() 64 | { 65 | x = 0.0; 66 | y = 0.0; 67 | } 68 | 69 | public bool IsValid() 70 | { 71 | return x > 0.0 && y > 0.0; 72 | } 73 | 74 | public bool NotValid() 75 | { 76 | return !IsValid(); 77 | } 78 | 79 | public DNGVector3 XYtoXYZ() 80 | { 81 | DNGxyCoord temp = new DNGxyCoord(this); 82 | 83 | // Restrict xy coord to someplace inside the range of real xy coordinates. 84 | // This prevents math from doing strange things when users specify 85 | // extreme temperature/tint coordinates. 86 | temp.x = DNGUtils.Pin(0.000001, temp.x, 0.999999); 87 | temp.y = DNGUtils.Pin(0.000001, temp.y, 0.999999); 88 | 89 | if (temp.x + temp.y > 0.999999) 90 | { 91 | double scale = 0.999999 / (temp.x + temp.y); 92 | temp.x *= scale; 93 | temp.y *= scale; 94 | } 95 | 96 | return new DNGVector3(temp.x / temp.y, 97 | 1.0, 98 | (1.0 - temp.x - temp.y) / temp.y); 99 | } 100 | 101 | public static DNGxyCoord XYZtoXY(DNGVector3 coord) 102 | { 103 | double X = coord[0]; 104 | double Y = coord[1]; 105 | double Z = coord[2]; 106 | 107 | double total = X + Y + Z; 108 | 109 | if (total > 0.0) 110 | { 111 | return new DNGxyCoord(X / total, Y / total); 112 | } 113 | 114 | return DNGxyCoord.D50; 115 | } 116 | 117 | public override bool Equals(object obj) 118 | { 119 | if (!(obj is DNGxyCoord)) 120 | { 121 | return false; 122 | } 123 | 124 | DNGxyCoord t = (DNGxyCoord)obj; 125 | return this.x == t.x && this.y == t.y; 126 | } 127 | 128 | public override int GetHashCode() 129 | { 130 | return x.GetHashCode() | y.GetHashCode(); 131 | } 132 | 133 | public static bool operator ==(DNGxyCoord a, DNGxyCoord b) 134 | { 135 | return a.x == b.x && a.y == b.y; 136 | } 137 | 138 | public static bool operator !=(DNGxyCoord a, DNGxyCoord b) 139 | { 140 | return a.x != b.x && a.y != b.y; 141 | } 142 | 143 | public static DNGxyCoord operator +(DNGxyCoord a, DNGxyCoord b) 144 | { 145 | return new DNGxyCoord(a.x + b.x, a.y + b.y); 146 | } 147 | 148 | public static DNGxyCoord operator -(DNGxyCoord a, DNGxyCoord b) 149 | { 150 | return new DNGxyCoord(a.x - b.x, a.y - b.y); 151 | } 152 | 153 | public static DNGxyCoord operator *(double scale, DNGxyCoord b) 154 | { 155 | return new DNGxyCoord(scale * b.x, scale * b.y); 156 | } 157 | 158 | public static DNGxyCoord operator *(DNGxyCoord a, double scale) 159 | { 160 | return new DNGxyCoord(a.x * scale, a.y * scale); 161 | } 162 | 163 | public static double operator *(DNGxyCoord a, DNGxyCoord b) 164 | { 165 | return a.x * b.x + a.y * a.y; 166 | } 167 | 168 | public static DNGxyCoord StdA 169 | { 170 | get 171 | { 172 | return new DNGxyCoord(0.4476, 0.4074); 173 | } 174 | } 175 | public static DNGxyCoord D50 176 | { 177 | get 178 | { 179 | return new DNGxyCoord(0.3457, 0.3585); 180 | } 181 | } 182 | 183 | public static DNGxyCoord D55 184 | { 185 | get 186 | { 187 | return new DNGxyCoord(0.3324, 0.3474); 188 | } 189 | } 190 | 191 | public static DNGxyCoord D65 192 | { 193 | get 194 | { 195 | return new DNGxyCoord(0.3127, 0.3290); 196 | } 197 | } 198 | 199 | public static DNGxyCoord D75 200 | { 201 | get 202 | { 203 | return new DNGxyCoord(0.2990, 0.3149); 204 | } 205 | } 206 | 207 | public static DNGxyCoord PCStoXY 208 | { 209 | get { return D50; } //using ProPhoto as intermediate RGB space 210 | } 211 | public static DNGVector3 PCStoXYZ 212 | { 213 | get { return D50.XYtoXYZ(); } 214 | } 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /PefFile/ExtraCameraProfiles.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | using System.Xml.Serialization; 25 | 26 | namespace PentaxPefFile 27 | { 28 | public class ExtraCameraProfiles 29 | { 30 | #region Seralization 31 | /// 32 | /// Saves to an xml file 33 | /// 34 | /// File path of the new xml file 35 | public void Save(string FileName) 36 | { 37 | using (var writer = new System.IO.StreamWriter(FileName)) 38 | { 39 | var serializer = new XmlSerializer(this.GetType()); 40 | serializer.Serialize(writer, this); 41 | writer.Flush(); 42 | } 43 | } 44 | 45 | /// 46 | /// Load an object from an xml file 47 | /// 48 | /// Xml file name 49 | /// The object created from the xml file 50 | public static ExtraCameraProfiles Load(string FileName) 51 | { 52 | using (var stream = System.IO.File.OpenRead(FileName)) 53 | { 54 | var serializer = new XmlSerializer(typeof(ExtraCameraProfiles)); 55 | return serializer.Deserialize(stream) as ExtraCameraProfiles; 56 | } 57 | } 58 | #endregion 59 | 60 | List extraCameraProfiles; 61 | 62 | public List Profiles 63 | { 64 | get { return extraCameraProfiles; } 65 | set { extraCameraProfiles = value; } 66 | } 67 | 68 | public ExtraCameraProfile GetProfile(string aMake, string aUniqueModel) 69 | { 70 | if (extraCameraProfiles == null) 71 | return null; 72 | 73 | for (int i = 0; i < extraCameraProfiles.Count; i++) 74 | { 75 | if (extraCameraProfiles[i].Make == aMake) 76 | { 77 | if (extraCameraProfiles[i].UniqueModel == aUniqueModel) 78 | { 79 | return extraCameraProfiles[i]; 80 | } 81 | } 82 | } 83 | return null; 84 | } 85 | } 86 | 87 | public class ExtraCameraProfile 88 | { 89 | string make; 90 | string uniqueModel; 91 | 92 | double[] colorMatrix1; 93 | double[] colorMatrix2; 94 | IFDDNGCalibrationIlluminant.Illuminant illuminant1; 95 | IFDDNGCalibrationIlluminant.Illuminant illuminant2; 96 | 97 | NoiseModel noiseModel; 98 | CropInfo cropInfo; 99 | 100 | public string Make 101 | { 102 | get { return make; } 103 | set { make = value; } 104 | } 105 | public string UniqueModel 106 | { 107 | get { return uniqueModel; } 108 | set { uniqueModel = value; } 109 | } 110 | public double[] ColorMatrix1 111 | { 112 | get { return colorMatrix1; } 113 | set { colorMatrix1 = value; } 114 | } 115 | public double[] ColorMatrix2 116 | { 117 | get { return colorMatrix2; } 118 | set { colorMatrix2 = value; } 119 | } 120 | public IFDDNGCalibrationIlluminant.Illuminant Illuminant1 121 | { 122 | get { return illuminant1; } 123 | set { illuminant1 = value; } 124 | } 125 | public IFDDNGCalibrationIlluminant.Illuminant Illuminant2 126 | { 127 | get { return illuminant2; } 128 | set { illuminant2 = value; } 129 | } 130 | public NoiseModel NoiseModel 131 | { 132 | get { return noiseModel; } 133 | set { noiseModel = value; } 134 | } 135 | public CropInfo CropInfo 136 | { 137 | get { return cropInfo; } 138 | set { cropInfo = value; } 139 | } 140 | } 141 | 142 | public class NoiseModel 143 | { 144 | int[] iso; 145 | double[] alpha; 146 | double[] beta; 147 | 148 | public int[] Iso 149 | { 150 | get { return iso; } 151 | set { iso = value; } 152 | } 153 | public double[] Alpha 154 | { 155 | get { return alpha; } 156 | set { alpha = value; } 157 | } 158 | public double[] Beta 159 | { 160 | get { return beta; } 161 | set { beta = value; } 162 | } 163 | 164 | public (double, double) GetValue(int aIso) 165 | { 166 | if (iso.Length == 0) 167 | { 168 | return (0, 0); 169 | } 170 | 171 | int index = -1; 172 | for (int i = iso.Length - 1; i >= 0; i--) 173 | { 174 | if (iso[i] <= aIso) 175 | { 176 | index = i; 177 | break; 178 | } 179 | } 180 | 181 | //found at last index 182 | if (index == iso.Length - 1) 183 | { 184 | return (alpha[iso.Length - 1], beta[iso.Length - 1]); 185 | } 186 | //or asked ISO is smaller than our model 187 | if (index < 0) 188 | { 189 | return (alpha[0], beta[0]); 190 | } 191 | 192 | //linear interpolate between two values 193 | double weight = ((double)aIso - (double)iso[index + 1]) / ((double)iso[index] - (double)iso[index + 1]); 194 | double a = weight * alpha[index] + (1.0 - weight) * alpha[index + 1]; 195 | double b = weight * beta[index] + (1.0 - weight) * beta[index + 1]; 196 | 197 | return (a, b); 198 | } 199 | } 200 | 201 | public class CropInfo 202 | { 203 | int top; 204 | int left; 205 | int width; 206 | int height; 207 | 208 | public int Top 209 | { 210 | get { return top; } 211 | set { top = value; } 212 | } 213 | public int Left 214 | { 215 | get { return left; } 216 | set { left = value; } 217 | } 218 | public int Width 219 | { 220 | get { return width; } 221 | set { width = value; } 222 | } 223 | public int Height 224 | { 225 | get { return height; } 226 | set { height = value; } 227 | } 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /PefFile/FileReader.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Text; 22 | using System.IO; 23 | using System.Runtime.InteropServices; 24 | 25 | namespace PentaxPefFile 26 | { 27 | public class FileReader 28 | { 29 | protected Stream mFile; 30 | protected BinaryReader mFileReader; 31 | protected string mFileName; 32 | protected bool mEndianSwap; 33 | 34 | public FileReader(string aFileName) 35 | { 36 | mFileName = aFileName; 37 | mFile = new FileStream(aFileName, FileMode.Open, FileAccess.Read); 38 | mFileReader = new BinaryReader(mFile); 39 | mEndianSwap = false; 40 | } 41 | 42 | public FileReader(Stream aFileStream) 43 | { 44 | mFile = aFileStream; 45 | mFileReader = new BinaryReader(mFile); 46 | mEndianSwap = false; 47 | } 48 | 49 | protected ushort Endian_swap(ushort x) 50 | { 51 | return (ushort)((x >> 8) | (x << 8)); 52 | } 53 | 54 | protected uint Endian_swap(uint x) 55 | { 56 | return (uint)((x >> 24) | 57 | ((x << 8) & 0x00FF0000) | 58 | ((x >> 8) & 0x0000FF00) | 59 | (x << 24)); 60 | } 61 | 62 | protected ulong Endian_swap(ulong x) 63 | { 64 | return (ulong)((x >> 56) | 65 | ((x << 40) & 0x00FF000000000000) | 66 | ((x << 24) & 0x0000FF0000000000) | 67 | ((x << 8) & 0x000000FF00000000) | 68 | ((x >> 8) & 0x00000000FF000000) | 69 | ((x >> 24) & 0x0000000000FF0000) | 70 | ((x >> 40) & 0x000000000000FF00) | 71 | (x << 56)); 72 | } 73 | 74 | protected unsafe short Endian_swap(short x) 75 | { 76 | ushort i = *(ushort*)&x; 77 | return (short)((i >> 8) | (i << 8)); 78 | } 79 | 80 | protected unsafe int Endian_swap(int x) 81 | { 82 | uint i = *(uint*)&x; 83 | return (int)((i >> 24) | 84 | ((i << 8) & 0x00FF0000) | 85 | ((i >> 8) & 0x0000FF00) | 86 | (i << 24)); 87 | } 88 | 89 | protected unsafe long Endian_swap(long x) 90 | { 91 | ulong i = *(ulong*)&x; 92 | return (long)((i >> 56) | 93 | ((i << 40) & 0x00FF000000000000) | 94 | ((i << 24) & 0x0000FF0000000000) | 95 | ((i << 8) & 0x000000FF00000000) | 96 | ((i >> 8) & 0x00000000FF000000) | 97 | ((i >> 24) & 0x0000000000FF0000) | 98 | ((i >> 40) & 0x000000000000FF00) | 99 | (i << 56)); 100 | } 101 | 102 | protected unsafe double Endian_swap(double x) 103 | { 104 | ulong i = *(ulong*)&x; 105 | i = (i >> 56) | 106 | ((i << 40) & 0x00FF000000000000) | 107 | ((i << 24) & 0x0000FF0000000000) | 108 | ((i << 8) & 0x000000FF00000000) | 109 | ((i >> 8) & 0x00000000FF000000) | 110 | ((i >> 24) & 0x0000000000FF0000) | 111 | ((i >> 40) & 0x000000000000FF00) | 112 | (i << 56); 113 | return *(double*)&i; 114 | } 115 | 116 | protected unsafe float Endian_swap(float x) 117 | { 118 | uint i = *(uint*)&x; 119 | i = (i >> 24) | 120 | ((i << 8) & 0x00FF0000) | 121 | ((i >> 8) & 0x0000FF00) | 122 | (i << 24); 123 | return *(float*)&i; 124 | } 125 | 126 | public long ReadI8() 127 | { 128 | long temp = mFileReader.ReadInt64(); 129 | if (mEndianSwap) temp = Endian_swap(temp); 130 | return temp; 131 | } 132 | 133 | public long ReadI8BE() 134 | { 135 | long temp = mFileReader.ReadInt64(); 136 | if (BitConverter.IsLittleEndian) temp = Endian_swap(temp); 137 | return temp; 138 | } 139 | 140 | public int ReadI4() 141 | { 142 | int temp = mFileReader.ReadInt32(); 143 | if (mEndianSwap) temp = Endian_swap(temp); 144 | return temp; 145 | } 146 | 147 | public int ReadI4BE() 148 | { 149 | int temp = mFileReader.ReadInt32(); 150 | if (BitConverter.IsLittleEndian) temp = Endian_swap(temp); 151 | return temp; 152 | } 153 | 154 | public short ReadI2() 155 | { 156 | short temp = mFileReader.ReadInt16(); 157 | if (mEndianSwap) temp = Endian_swap(temp); 158 | return temp; 159 | } 160 | 161 | public short ReadI2BE() 162 | { 163 | short temp = mFileReader.ReadInt16(); 164 | if (BitConverter.IsLittleEndian) temp = Endian_swap(temp); 165 | return temp; 166 | } 167 | 168 | public sbyte ReadI1() 169 | { 170 | sbyte temp = mFileReader.ReadSByte(); 171 | return temp; 172 | } 173 | 174 | public ulong ReadUI8() 175 | { 176 | ulong temp = mFileReader.ReadUInt64(); 177 | if (mEndianSwap) temp = Endian_swap(temp); 178 | return temp; 179 | } 180 | 181 | public ulong ReadUI8BE() 182 | { 183 | ulong temp = mFileReader.ReadUInt64(); 184 | if (BitConverter.IsLittleEndian) temp = Endian_swap(temp); 185 | return temp; 186 | } 187 | 188 | public uint ReadUI4() 189 | { 190 | uint temp = mFileReader.ReadUInt32(); 191 | if (mEndianSwap) temp = Endian_swap(temp); 192 | return temp; 193 | } 194 | 195 | public uint ReadUI4BE() 196 | { 197 | uint temp = mFileReader.ReadUInt32(); 198 | if (BitConverter.IsLittleEndian) temp = Endian_swap(temp); 199 | return temp; 200 | } 201 | 202 | public ushort ReadUI2() 203 | { 204 | ushort temp = mFileReader.ReadUInt16(); 205 | if (mEndianSwap) temp = Endian_swap(temp); 206 | return temp; 207 | } 208 | 209 | public ushort ReadUI2BE() 210 | { 211 | ushort temp = mFileReader.ReadUInt16(); 212 | if (BitConverter.IsLittleEndian) temp = Endian_swap(temp); 213 | return temp; 214 | } 215 | 216 | public byte ReadUI1() 217 | { 218 | byte temp = mFileReader.ReadByte(); 219 | return temp; 220 | } 221 | 222 | public float ReadF4() 223 | { 224 | float temp = mFileReader.ReadSingle(); 225 | if (mEndianSwap) temp = Endian_swap(temp); 226 | return temp; 227 | } 228 | 229 | public float ReadF4BE() 230 | { 231 | float temp = mFileReader.ReadSingle(); 232 | if (BitConverter.IsLittleEndian) temp = Endian_swap(temp); 233 | return temp; 234 | } 235 | 236 | public double ReadF8() 237 | { 238 | double temp = mFileReader.ReadDouble(); 239 | if (mEndianSwap) temp = Endian_swap(temp); 240 | return temp; 241 | } 242 | 243 | public double ReadF8BE() 244 | { 245 | double temp = mFileReader.ReadDouble(); 246 | if (BitConverter.IsLittleEndian) temp = Endian_swap(temp); 247 | return temp; 248 | } 249 | 250 | public string ReadStr(int aCountBytes) 251 | { 252 | byte[] arr = mFileReader.ReadBytes(aCountBytes); 253 | System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); 254 | return enc.GetString(arr); 255 | } 256 | 257 | public void Close() 258 | { 259 | mFileReader.Close(); 260 | mFile.Close(); 261 | } 262 | 263 | public void Seek(uint aPosition, SeekOrigin aOrigin) 264 | { 265 | mFile.Seek(aPosition, aOrigin); 266 | } 267 | 268 | public uint Position() 269 | { 270 | return (uint)mFile.Position; 271 | } 272 | 273 | public bool EndianSwap 274 | { 275 | get { return mEndianSwap; } 276 | } 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /PefFile/ImageFileDirectory.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | using System.IO; 25 | 26 | namespace PentaxPefFile 27 | { 28 | public class ImageFileDirectory 29 | { 30 | private FileReader mPefFile; 31 | private ushort mEntryCount; 32 | public List mEntries; 33 | 34 | public ImageFileDirectory(FileReader aPefFile) 35 | { 36 | mPefFile = aPefFile; 37 | mEntries = new List(); 38 | mEntryCount = mPefFile.ReadUI2(); 39 | for (ushort i = 0; i < mEntryCount; i++) 40 | { 41 | ImageFileDirectoryEntry entry = ImageFileDirectoryEntry.CreateImageFileDirectoryEntry(mPefFile); 42 | mEntries.Add(entry); 43 | } 44 | } 45 | 46 | public T GetEntry() where T : ImageFileDirectoryEntry 47 | { 48 | Type t = typeof(T); 49 | foreach (var item in mEntries) 50 | { 51 | if (item is T) 52 | return (T)item; 53 | } 54 | return null; 55 | } 56 | 57 | internal void SavePass1(Stream stream) 58 | { 59 | stream.Write(BitConverter.GetBytes((ushort)mEntries.Count), 0, 2); 60 | for (int i = 0; i < mEntries.Count; i++) 61 | { 62 | mEntries[i].SavePass1(stream); 63 | } 64 | } 65 | 66 | internal void SavePass2(Stream stream) 67 | { 68 | //end of IFDs marker 69 | //stream.Write(new byte[] { 0, 0, 0, 0 }, 0, 4); 70 | for (int i = 0; i < mEntries.Count; i++) 71 | { 72 | mEntries[i].SavePass2(stream); 73 | } 74 | } 75 | 76 | public ImageFileDirectory(uint width, uint height) 77 | { 78 | mEntries = new List(); 79 | 80 | mEntries.Add(new IFDImageWidth(width)); 81 | mEntries.Add(new IFDImageLength(height)); 82 | mEntries.Add(new IFDBitsPerSample(new ushort[] { 16, 16, 16})); 83 | mEntries.Add(new IFDCompression(IFDCompression.Compression.NoCompression)); 84 | mEntries.Add(new IFDPhotometricInterpretation(IFDPhotometricInterpretation.PhotometricInterpretation.RGB)); 85 | mEntries.Add(new IFDStripOffsets(new uint[] { 0 })); 86 | mEntries.Add(new IFDSamplesPerPixel(3)); 87 | mEntries.Add(new IFDRowsPerStrip(height)); 88 | mEntries.Add(new IFDStripByteCounts(new uint[] { width * height * 3 * 2 })); 89 | mEntries.Add(new IFDXResolution(new Rational(720, 10))); 90 | mEntries.Add(new IFDYResolution(new Rational(720, 10))); 91 | mEntries.Add(new IFDResolutionUnit(IFDResolutionUnit.ResolutionUnit.None)); 92 | mEntries.Add(new IFDMake("MK TIFF")); 93 | mEntryCount = (ushort)mEntries.Count; 94 | } 95 | 96 | public void SaveAsTiff(string aFilename, ushort[] data) 97 | { 98 | FileStream fs = new FileStream(aFilename, FileMode.Create, FileAccess.Write); 99 | fs.Write(new byte[] { 0x49, 0x49, 0x2A, 00, 8, 0, 0, 0 }, 0, 8); //Tiff header with offset to first IFD=8 100 | fs.Write(BitConverter.GetBytes(mEntryCount), 0, 2); 101 | foreach (var item in mEntries) 102 | { 103 | fs.Flush(); 104 | item.SavePass1(fs); 105 | } 106 | fs.Write(new byte[] { 0, 0, 0, 0 }, 0, 4); 107 | foreach (var item in mEntries) 108 | { 109 | item.SavePass2(fs); 110 | } 111 | fs.Seek(0, SeekOrigin.End); 112 | uint finalImageOffset = (uint)fs.Position; 113 | GetEntry().SaveFinalOffsets(fs, new uint[] { finalImageOffset }); 114 | fs.Seek(finalImageOffset, SeekOrigin.Begin); 115 | BinaryWriter br = new BinaryWriter(fs); 116 | for (int i = 0; i < data.Length; i++) 117 | { 118 | br.Write(data[i]); 119 | } 120 | br.Close(); 121 | br.Dispose(); 122 | fs.Close(); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /PefFile/PefFile.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {CEB1FFE5-2BA8-48AA-AC87-7C5FB5CC01B4} 8 | Library 9 | Properties 10 | PentaxPefFile 11 | PefFile 12 | v4.7.2 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | true 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | true 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /PefFile/PentaxMakerNotes.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.IO; 22 | using System.Linq; 23 | using System.Text; 24 | using System.Threading.Tasks; 25 | 26 | namespace PentaxPefFile 27 | { 28 | public class PentaxMakerNotes : FileReader 29 | { 30 | List mEntries; 31 | ushort mEntryCount; 32 | public bool K3Specific = false; 33 | //the "AOC" makenotes uses absolute offsets to file beginning, not in makernote. 34 | //hence subtract that offset... 35 | int mAdditionalOffset; 36 | 37 | public void SeekWithOffset(uint aPosition, SeekOrigin aOrigin) 38 | { 39 | base.Seek((uint)((int)aPosition - mAdditionalOffset), aOrigin); 40 | } 41 | 42 | public PentaxMakerNotes(byte[] aData, uint offset) 43 | : base(new MemoryStream(aData)) 44 | { 45 | //FileStream fs = new FileStream("dumpMakerNote.bin", FileMode.Create, FileAccess.Write); 46 | //fs.Write(aData, 0, aData.Length); 47 | //fs.Close(); 48 | 49 | 50 | mAdditionalOffset = 0; 51 | mEntries = new List(); 52 | 53 | string testVersion = ReadStr(4); 54 | if (testVersion == "AOC\0") 55 | { 56 | byte a = mFileReader.ReadByte(); 57 | byte b = mFileReader.ReadByte(); 58 | 59 | bool fileIsLittleEndian; 60 | if (a == b && b == 'I') 61 | fileIsLittleEndian = true; 62 | else 63 | if (a == b && b == 'M') 64 | fileIsLittleEndian = false; 65 | else 66 | throw new FileLoadException("Could not determine file endianess for maker notes"); 67 | 68 | mEndianSwap = fileIsLittleEndian != BitConverter.IsLittleEndian; 69 | mAdditionalOffset = (int)offset; 70 | } 71 | else 72 | { 73 | Seek(0, SeekOrigin.Begin); 74 | testVersion = ReadStr(8); 75 | if (testVersion == "PENTAX \0") 76 | { 77 | byte a = mFileReader.ReadByte(); 78 | byte b = mFileReader.ReadByte(); 79 | 80 | bool fileIsLittleEndian; 81 | if (a == b && b == 'I') 82 | fileIsLittleEndian = true; 83 | else 84 | if (a == b && b == 'M') 85 | fileIsLittleEndian = false; 86 | else 87 | throw new FileLoadException("Could not determine file endianess for maker notes"); 88 | 89 | mEndianSwap = fileIsLittleEndian != BitConverter.IsLittleEndian; 90 | } 91 | else 92 | { 93 | Seek(0, SeekOrigin.Begin); 94 | testVersion = ReadStr(10); 95 | const int SizeAdobeHeader = 20; 96 | if (testVersion == "Adobe\0MakN") 97 | { 98 | uint byteCount = mFileReader.ReadUInt32(); 99 | if (BitConverter.IsLittleEndian) 100 | { 101 | byteCount = ((byteCount >> 24) | 102 | ((byteCount << 8) & 0x00FF0000) | 103 | ((byteCount >> 8) & 0x0000FF00) | 104 | (byteCount << 24)); 105 | } 106 | 107 | byte a = mFileReader.ReadByte(); 108 | byte b = mFileReader.ReadByte(); 109 | 110 | bool fileIsLittleEndian; 111 | if (a == b && b == 'I') 112 | fileIsLittleEndian = true; 113 | else 114 | if (a == b && b == 'M') 115 | fileIsLittleEndian = false; 116 | else 117 | throw new FileLoadException("Could not determine file endianess for maker notes"); 118 | 119 | mEndianSwap = fileIsLittleEndian != BitConverter.IsLittleEndian; 120 | 121 | uint temp = mFileReader.ReadUInt32(); 122 | if (mEndianSwap) 123 | { 124 | temp = ((temp >> 24) | 125 | ((temp << 8) & 0x00FF0000) | 126 | ((temp >> 8) & 0x0000FF00) | 127 | (temp << 24)); 128 | } 129 | mAdditionalOffset = (int)temp; 130 | 131 | 132 | 133 | 134 | 135 | testVersion = ReadStr(4); 136 | if (testVersion == "AOC\0") 137 | { 138 | a = mFileReader.ReadByte(); 139 | b = mFileReader.ReadByte(); 140 | 141 | 142 | if (a == b && b == 'I') 143 | fileIsLittleEndian = true; 144 | else 145 | if (a == b && b == 'M') 146 | fileIsLittleEndian = false; 147 | else 148 | throw new FileLoadException("Could not determine file endianess for maker notes"); 149 | 150 | mEndianSwap = fileIsLittleEndian != BitConverter.IsLittleEndian; 151 | mAdditionalOffset -= SizeAdobeHeader; 152 | } 153 | else 154 | { 155 | Seek(Position() - 4, SeekOrigin.Begin); 156 | testVersion = ReadStr(8); 157 | if (testVersion == "PENTAX \0") 158 | { 159 | a = mFileReader.ReadByte(); 160 | b = mFileReader.ReadByte(); 161 | 162 | 163 | if (a == b && b == 'I') 164 | fileIsLittleEndian = true; 165 | else 166 | if (a == b && b == 'M') 167 | fileIsLittleEndian = false; 168 | else 169 | throw new FileLoadException("Could not determine file endianess for maker notes"); 170 | 171 | mEndianSwap = fileIsLittleEndian != BitConverter.IsLittleEndian; 172 | mAdditionalOffset = -SizeAdobeHeader; 173 | } 174 | } 175 | /* Following Exiftool: 176 | 1. Six bytes containing the zero-terminated string "Adobe". (The DNG specification calls for the DNGPrivateData tag to start with an ASCII string identifying the creator/format). 177 | 2. 4 bytes: an ASCII string ("MakN" for a Makernote), indicating what sort of data is being stored here. Note that this is not zero-terminated. 178 | 3. A four-byte count (number of data bytes following); this is the length of the original MakerNote data. (This is always in "most significant byte first" format). 179 | 4. 2 bytes: the byte-order indicator from the original file (the usual 'MM'/4D4D or 'II'/4949). 180 | 5. 4 bytes: the original file offset for the MakerNote tag data (stored according to the byte order given above). 181 | 6. The contents of the MakerNote tag. This is a simple byte-for-byte copy, with no modification. 182 | */ 183 | } 184 | else 185 | { 186 | return; //Not a Pentax make note, can't handle it... 187 | } 188 | } 189 | } 190 | 191 | mEntryCount = ReadUI2(); 192 | for (ushort i = 0; i < mEntryCount; i++) 193 | { 194 | PentaxMakerNotesEntry entry = PentaxMakerNotesEntry.CreatePentaxMakerNotesEntry(this); 195 | mEntries.Add(entry); 196 | } 197 | 198 | //MNPreviewImageSize imagesize = GetEntry(); 199 | //MNPreviewImageLength imagelength = GetEntry(); 200 | //MNPreviewImageStart imagestart = GetEntry(); 201 | //MNPreviewImageBorders imageborder = GetEntry(); 202 | 203 | //uint curPos = Position(); 204 | //Seek(imagestart.Value, SeekOrigin.Begin); 205 | //byte[] data = mFileReader.ReadBytes((int)imagelength.Value); 206 | //Seek(curPos, SeekOrigin.Begin); 207 | 208 | } 209 | 210 | public T GetEntry() where T : PentaxMakerNotesEntry 211 | { 212 | Type t = typeof(T); 213 | foreach (var item in mEntries) 214 | { 215 | if (item is T) 216 | return (T)item; 217 | } 218 | return null; 219 | } 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /PefFile/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Allgemeine Informationen über eine Assembly werden über die folgenden 6 | // Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, 7 | // die einer Assembly zugeordnet sind. 8 | [assembly: AssemblyTitle("PefFile")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("PefFile")] 13 | [assembly: AssemblyCopyright("Copyright © 2019")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly 18 | // für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von 19 | // COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. 20 | [assembly: ComVisible(false)] 21 | 22 | // Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird 23 | [assembly: Guid("ceb1ffe5-2ba8-48aa-ac87-7c5fb5cc01b4")] 24 | 25 | // Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: 26 | // 27 | // Hauptversion 28 | // Nebenversion 29 | // Buildnummer 30 | // Revision 31 | // 32 | // Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, 33 | // indem Sie "*" wie unten gezeigt eingeben: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /PefFile/RawFile.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.IO; 22 | using System.Linq; 23 | using System.Text; 24 | using System.Threading.Tasks; 25 | 26 | namespace PentaxPefFile 27 | { 28 | public abstract class RawFile : FileReader 29 | { 30 | public enum BayerColor : int 31 | { 32 | Red = 0, 33 | Green = 1, 34 | Blue = 2, 35 | Cyan = 3, 36 | Magenta = 4, 37 | Yellow = 5, 38 | White = 6 39 | } 40 | 41 | public RawFile(string aFileName) 42 | : base(aFileName) 43 | { 44 | //set some default values: 45 | 46 | //color channels are assumed in order RGB if no tag present 47 | mColorTwist = new float[3,4]; 48 | mColorTwist[0, 0] = 1.0f; 49 | mColorTwist[1, 1] = 1.0f; 50 | mColorTwist[2, 2] = 1.0f; 51 | mColorTwistIsIdentity = true; 52 | 53 | //it seems as if only Pentax is capable of giving us that info 54 | mRollAnglePresent = false; 55 | mRecordingDate = new DateTime(); 56 | 57 | //read all IFDs/Tags: 58 | byte a = mFileReader.ReadByte(); 59 | byte b = mFileReader.ReadByte(); 60 | 61 | bool fileIsLittleEndian; 62 | if (a == b && b == 'I') 63 | fileIsLittleEndian = true; 64 | else 65 | if (a == b && b == 'M') 66 | fileIsLittleEndian = false; 67 | else 68 | throw new FileLoadException("Could not determine file endianess. Is this a proper TIFF/PEF/DNG file?", aFileName); 69 | 70 | mEndianSwap = fileIsLittleEndian != BitConverter.IsLittleEndian; 71 | 72 | ushort magicNumber = ReadUI2(); 73 | 74 | if (magicNumber != 42) 75 | throw new FileLoadException("This is not a valid TIFF/PEF/DNG file: Magic number is not 42.", aFileName); 76 | 77 | uint offsetToFirstIFD = ReadUI4(); 78 | 79 | mFile.Seek(offsetToFirstIFD, SeekOrigin.Begin); 80 | mIfds = new List(); 81 | while (true) 82 | { 83 | ImageFileDirectory ifd = new ImageFileDirectory(this); 84 | mIfds.Add(ifd); 85 | uint offsetToNext = ReadUI4(); 86 | if (offsetToNext == 0) 87 | break; 88 | Seek(offsetToNext, System.IO.SeekOrigin.Begin); 89 | } 90 | 91 | //until here PEF and DNG are the same. They diverge on how to read the tags 92 | } 93 | 94 | protected List mIfds; 95 | protected DNGColorSpec mColorSpec; 96 | protected DNGOrientation mOrientation; 97 | protected ushort[,] mRawImage; 98 | protected int mWidth; 99 | protected int mHeight; 100 | protected int mCropLeft; 101 | protected int mCropTop; 102 | protected int mCroppedWidth; 103 | protected int mCroppedHeight; 104 | protected int mBitDepth; 105 | protected int mISO; 106 | protected BayerColor[] mBayerPattern; 107 | protected float[,] mColorTwist; 108 | protected bool mColorTwistIsIdentity; 109 | protected float[] mWhiteLevel; 110 | protected float[] mBlackLevel; 111 | protected float[] mWhiteBalance; 112 | protected float mRollAngle; 113 | protected bool mRollAnglePresent; 114 | protected float mNoiseModelAlpha; 115 | protected float mNoiseModelBeta; 116 | protected Rational mExposureTime; 117 | protected DateTime mRecordingDate; 118 | protected string mMake; 119 | protected string mUniqueModelName; 120 | 121 | 122 | 123 | 124 | public ushort[,] RawImage 125 | { 126 | get { return mRawImage; } 127 | } 128 | public int RawWidth 129 | { 130 | get { return mWidth; } 131 | } 132 | public int RawHeight 133 | { 134 | get { return mHeight; } 135 | } 136 | public int CropLeft 137 | { 138 | get { return mCropLeft; } 139 | } 140 | public int CropTop 141 | { 142 | get { return mCropTop; } 143 | } 144 | public int CroppedWidth 145 | { 146 | get { return mCroppedWidth; } 147 | } 148 | public int CroppedHeight 149 | { 150 | get { return mCroppedHeight; } 151 | } 152 | public DNGOrientation Orientation 153 | { 154 | get { return mOrientation; } 155 | } 156 | public float[,] ColorTwist 157 | { 158 | get { return mColorTwist; } 159 | } 160 | public bool ColorTwistIsIdentity 161 | { 162 | get { return mColorTwistIsIdentity; } 163 | } 164 | public BayerColor[] BayerPattern 165 | { 166 | get { return mBayerPattern; } 167 | } 168 | public float RollAngle 169 | { 170 | get { return mRollAngle; } 171 | } 172 | public bool RollAnglePresent 173 | { 174 | get { return mRollAnglePresent; } 175 | } 176 | public Rational ExposureTime 177 | { 178 | get { return mExposureTime; } 179 | } 180 | public DateTime RecordingDate 181 | { 182 | get { return mRecordingDate; } 183 | } 184 | 185 | /// 186 | /// In R G B order 187 | /// 188 | public float[] WhiteLevel 189 | { 190 | get { return mWhiteLevel; } 191 | } 192 | /// 193 | /// In R G B order 194 | /// 195 | public float[] BlackLevel 196 | { 197 | get { return mBlackLevel; } 198 | } 199 | /// 200 | /// In R G B order 201 | /// 202 | public float[] WhiteBalance 203 | { 204 | get { return mWhiteBalance; } 205 | } 206 | public int ISO 207 | { 208 | get { return mISO; } 209 | } 210 | 211 | public float NoiseModelAlpha 212 | { 213 | get { return mNoiseModelAlpha; } 214 | } 215 | 216 | public float NoiseModelBeta 217 | { 218 | get { return mNoiseModelBeta; } 219 | } 220 | 221 | public string Make 222 | { 223 | get { return mMake; } 224 | } 225 | 226 | public string UniqueModelName 227 | { 228 | get { return mUniqueModelName; } 229 | } 230 | 231 | public DNGColorSpec ColorSpec 232 | { 233 | get { return mColorSpec; } 234 | } 235 | 236 | public bool LoadExtraCameraProfile(string xmlFileName) 237 | { 238 | PentaxPefFile.ExtraCameraProfiles extraCameraProfiles = PentaxPefFile.ExtraCameraProfiles.Load(xmlFileName); 239 | PentaxPefFile.ExtraCameraProfile p = extraCameraProfiles.GetProfile(mMake, mUniqueModelName); 240 | 241 | bool setAnything = false; 242 | if (p == null) 243 | { 244 | return false; 245 | } 246 | 247 | if (p.CropInfo != null) 248 | { 249 | int cropLeft = p.CropInfo.Left; 250 | int cropTop = p.CropInfo.Top; 251 | 252 | int croppedWidth = p.CropInfo.Width; 253 | int croppedHeight = p.CropInfo.Height; 254 | 255 | //we always crop at least two pixels because of our algos... 256 | mCropLeft = Math.Max(2, cropLeft); 257 | mCropTop = Math.Max(2, cropTop); 258 | 259 | mCroppedWidth = croppedWidth - Math.Max(0, (cropLeft + croppedWidth) - (mWidth - 2)); 260 | mCroppedHeight = croppedHeight - Math.Max(0, (cropTop + croppedHeight) - (mHeight - 2)); 261 | setAnything = true; 262 | } 263 | 264 | if (p.ColorMatrix1 != null) 265 | { 266 | mColorSpec = new DNGColorSpec(p.ColorMatrix1, p.ColorMatrix2, p.Illuminant1, p.Illuminant2, mWhiteBalance); 267 | setAnything = true; 268 | } 269 | 270 | if (p.NoiseModel != null) 271 | { 272 | double a, b; 273 | (a, b) = p.NoiseModel.GetValue(mISO); 274 | mNoiseModelAlpha = (float)a; 275 | mNoiseModelBeta = (float)b; 276 | setAnything = true; 277 | } 278 | return setAnything; 279 | } 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /PefFile/SaveTiffTag.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.IO; 23 | using System.Text; 24 | using System.Threading.Tasks; 25 | 26 | namespace PentaxPefFile 27 | { 28 | public abstract class SaveTiffTag 29 | { 30 | protected uint mOffsetInStream; 31 | 32 | public virtual void SavePass1(Stream stream) 33 | { 34 | //do nothing 35 | } 36 | public virtual void SavePass2(Stream stream) 37 | { 38 | //do nothing 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /PefFile/TIFFValueTypes.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2020, Michael Kunz. All rights reserved. 2 | // https://github.com/kunzmi/ImageStackAlignator 3 | // 4 | // This file is part of ImageStackAlignator. 5 | // 6 | // ImageStackAlignator is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU Lesser General Public License as 8 | // published by the Free Software Foundation, version 3. 9 | // 10 | // ImageStackAlignator is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 18 | // MA 02110-1301 USA, http://www.gnu.org/licenses/. 19 | using System; 20 | using System.Collections.Generic; 21 | using System.Linq; 22 | using System.Text; 23 | using System.Threading.Tasks; 24 | 25 | namespace PentaxPefFile 26 | { 27 | public enum TIFFValueTypes : ushort 28 | { 29 | Byte = 1, 30 | Ascii = 2, 31 | UnsignedShort = 3, 32 | UnsignedLong = 4, 33 | Rational = 5, 34 | SignedByte = 6, 35 | Undefined = 7, 36 | SignedShort = 8, 37 | SignedLong = 9, 38 | SignedRational = 10, 39 | Float = 11, 40 | Double = 12 41 | } 42 | 43 | public struct Rational 44 | { 45 | public uint numerator; 46 | public uint denominator; 47 | 48 | public Rational(uint[] aValues) 49 | { 50 | if (aValues.Length < 2) 51 | throw new ArgumentException("aValues must contain at least two values."); 52 | 53 | numerator = aValues[0]; 54 | denominator = aValues[1]; 55 | } 56 | 57 | public Rational(uint aNominator, uint aDenominator) 58 | { 59 | numerator = aNominator; 60 | denominator = aDenominator; 61 | } 62 | 63 | public override string ToString() 64 | { 65 | return numerator.ToString() + " / " + denominator.ToString(); 66 | } 67 | 68 | public double Value 69 | { 70 | get { return (double)numerator / (double)denominator; } 71 | } 72 | } 73 | 74 | public struct SRational 75 | { 76 | public int numerator; 77 | public int denominator; 78 | 79 | public SRational(int[] aValues) 80 | { 81 | if (aValues.Length < 2) 82 | throw new ArgumentException("aValues must contain at least two values."); 83 | 84 | numerator = aValues[0]; 85 | denominator = aValues[1]; 86 | } 87 | 88 | public SRational(int aNominator, int aDenominator) 89 | { 90 | numerator = aNominator; 91 | denominator = aDenominator; 92 | } 93 | 94 | public override string ToString() 95 | { 96 | return numerator.ToString() + " / " + denominator.ToString(); 97 | } 98 | 99 | public double Value 100 | { 101 | get { return (double)numerator / (double)denominator; } 102 | } 103 | } 104 | 105 | public struct TIFFValueType 106 | { 107 | TIFFValueTypes mType; 108 | public TIFFValueType(TIFFValueTypes aType) 109 | { 110 | mType = aType; 111 | } 112 | 113 | public int SizeInBytes 114 | { 115 | get 116 | { 117 | switch (mType) 118 | { 119 | case TIFFValueTypes.Byte: 120 | return 1; 121 | case TIFFValueTypes.Ascii: 122 | return 1; 123 | case TIFFValueTypes.UnsignedShort: 124 | return 2; 125 | case TIFFValueTypes.UnsignedLong: 126 | return 4; 127 | case TIFFValueTypes.Rational: 128 | return 8; 129 | case TIFFValueTypes.SignedByte: 130 | return 1; 131 | case TIFFValueTypes.Undefined: 132 | return 1; 133 | case TIFFValueTypes.SignedShort: 134 | return 2; 135 | case TIFFValueTypes.SignedLong: 136 | return 4; 137 | case TIFFValueTypes.SignedRational: 138 | return 8; 139 | case TIFFValueTypes.Float: 140 | return 4; 141 | case TIFFValueTypes.Double: 142 | return 8; 143 | default: 144 | throw new ArgumentException(mType.ToString() + " is not a valid type."); //Never happens... 145 | } 146 | } 147 | } 148 | 149 | public ushort GetValue() 150 | { 151 | return (ushort)mType; 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /TestingGoogleSuperRes.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29230.47 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Kernels", "Kernels\Kernels.vcxproj", "{80B85EE4-5AE5-4FD5-80ED-274F7E913606}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PefFile", "PefFile\PefFile.csproj", "{CEB1FFE5-2BA8-48AA-AC87-7C5FB5CC01B4}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PEFStudioDX", "PEFStudioDX\PEFStudioDX.csproj", "{DB59DD92-0B30-4A14-B494-29E0FF37E48C}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x64 = Debug|x64 16 | Release|Any CPU = Release|Any CPU 17 | Release|x64 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {80B85EE4-5AE5-4FD5-80ED-274F7E913606}.Debug|Any CPU.ActiveCfg = Debug|x64 21 | {80B85EE4-5AE5-4FD5-80ED-274F7E913606}.Debug|x64.ActiveCfg = Debug|x64 22 | {80B85EE4-5AE5-4FD5-80ED-274F7E913606}.Debug|x64.Build.0 = Debug|x64 23 | {80B85EE4-5AE5-4FD5-80ED-274F7E913606}.Release|Any CPU.ActiveCfg = Release|x64 24 | {80B85EE4-5AE5-4FD5-80ED-274F7E913606}.Release|x64.ActiveCfg = Release|x64 25 | {80B85EE4-5AE5-4FD5-80ED-274F7E913606}.Release|x64.Build.0 = Release|x64 26 | {CEB1FFE5-2BA8-48AA-AC87-7C5FB5CC01B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {CEB1FFE5-2BA8-48AA-AC87-7C5FB5CC01B4}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {CEB1FFE5-2BA8-48AA-AC87-7C5FB5CC01B4}.Debug|x64.ActiveCfg = Debug|Any CPU 29 | {CEB1FFE5-2BA8-48AA-AC87-7C5FB5CC01B4}.Debug|x64.Build.0 = Debug|Any CPU 30 | {CEB1FFE5-2BA8-48AA-AC87-7C5FB5CC01B4}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {CEB1FFE5-2BA8-48AA-AC87-7C5FB5CC01B4}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {CEB1FFE5-2BA8-48AA-AC87-7C5FB5CC01B4}.Release|x64.ActiveCfg = Release|Any CPU 33 | {CEB1FFE5-2BA8-48AA-AC87-7C5FB5CC01B4}.Release|x64.Build.0 = Release|Any CPU 34 | {DB59DD92-0B30-4A14-B494-29E0FF37E48C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {DB59DD92-0B30-4A14-B494-29E0FF37E48C}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {DB59DD92-0B30-4A14-B494-29E0FF37E48C}.Debug|x64.ActiveCfg = Debug|Any CPU 37 | {DB59DD92-0B30-4A14-B494-29E0FF37E48C}.Debug|x64.Build.0 = Debug|Any CPU 38 | {DB59DD92-0B30-4A14-B494-29E0FF37E48C}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {DB59DD92-0B30-4A14-B494-29E0FF37E48C}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {DB59DD92-0B30-4A14-B494-29E0FF37E48C}.Release|x64.ActiveCfg = Release|Any CPU 41 | {DB59DD92-0B30-4A14-B494-29E0FF37E48C}.Release|x64.Build.0 = Release|Any CPU 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | GlobalSection(ExtensibilityGlobals) = postSolution 47 | SolutionGuid = {170BAA05-5076-43F3-9F33-8D415A843B34} 48 | EndGlobalSection 49 | EndGlobal 50 | -------------------------------------------------------------------------------- /pictures/AdobeCrop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/AdobeCrop.png -------------------------------------------------------------------------------- /pictures/SuperResCrop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/SuperResCrop.png -------------------------------------------------------------------------------- /pictures/alpha.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/alpha.gif -------------------------------------------------------------------------------- /pictures/app1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/app1.png -------------------------------------------------------------------------------- /pictures/app2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/app2.png -------------------------------------------------------------------------------- /pictures/app21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/app21.png -------------------------------------------------------------------------------- /pictures/app3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/app3.png -------------------------------------------------------------------------------- /pictures/app4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/app4.png -------------------------------------------------------------------------------- /pictures/app5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/app5.png -------------------------------------------------------------------------------- /pictures/beta.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/beta.gif -------------------------------------------------------------------------------- /pictures/dmd.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/dmd.gif -------------------------------------------------------------------------------- /pictures/dms.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/dms.gif -------------------------------------------------------------------------------- /pictures/edge.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/edge.gif -------------------------------------------------------------------------------- /pictures/fraclam1lam2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/fraclam1lam2.gif -------------------------------------------------------------------------------- /pictures/grandCanyon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/grandCanyon.png -------------------------------------------------------------------------------- /pictures/lam1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/lam1.gif -------------------------------------------------------------------------------- /pictures/lam2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/lam2.gif -------------------------------------------------------------------------------- /pictures/newyorkFrame3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/newyorkFrame3.png -------------------------------------------------------------------------------- /pictures/newyorkFrame3Crop1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/newyorkFrame3Crop1.png -------------------------------------------------------------------------------- /pictures/newyorkMerged.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/newyorkMerged.png -------------------------------------------------------------------------------- /pictures/newyorkMergedCrop1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/newyorkMergedCrop1.png -------------------------------------------------------------------------------- /pictures/noiseModel.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/noiseModel.gif -------------------------------------------------------------------------------- /pictures/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/overview.png -------------------------------------------------------------------------------- /pictures/samsung.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/samsung.png -------------------------------------------------------------------------------- /pictures/sigmamd.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/sigmamd.gif -------------------------------------------------------------------------------- /pictures/sigmamdsqrt2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/sigmamdsqrt2.gif -------------------------------------------------------------------------------- /pictures/sigmams.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/sigmams.gif -------------------------------------------------------------------------------- /pictures/sigmamssqrt2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/sigmamssqrt2.gif -------------------------------------------------------------------------------- /pictures/sqrt2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/sqrt2.gif -------------------------------------------------------------------------------- /pictures/superRes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/superRes.png -------------------------------------------------------------------------------- /pictures/x.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kunzmi/ImageStackAlignator/b12e86e835742a99fbe8929d4b3692ba9bb537c0/pictures/x.gif --------------------------------------------------------------------------------