7
7
8
8
namespace Aardvark . OpenCV
9
9
{
10
+ #region Utilities
11
+
10
12
internal readonly struct GCHandleDiposable : IDisposable
11
13
{
12
14
public GCHandle Handle { get ; }
@@ -40,33 +42,63 @@ public static MatType ToMatType(this Type type, int channels)
40
42
else throw new NotSupportedException ( $ "Channel type { type } is not supported.") ;
41
43
}
42
44
43
- private static readonly Dictionary < ImageInterpolation , InterpolationFlags > interpolationFlags = new ( )
45
+ public static InterpolationFlags ToInterpolationFlags ( this ImageInterpolation interpolation , bool exact )
46
+ => interpolation switch
47
+ {
48
+ ImageInterpolation . Near when exact => ( InterpolationFlags ) 6 ,
49
+ ImageInterpolation . Near => InterpolationFlags . Nearest ,
50
+ ImageInterpolation . Linear when exact => InterpolationFlags . LinearExact ,
51
+ ImageInterpolation . Linear => InterpolationFlags . Linear ,
52
+ ImageInterpolation . Cubic => InterpolationFlags . Cubic ,
53
+ ImageInterpolation . Lanczos => InterpolationFlags . Lanczos4 ,
54
+ _ => throw new NotSupportedException ( $ "Filter { interpolation } is not supported.")
55
+ } ;
56
+
57
+ public static BorderTypes ToBorderTypes ( this ImageBorderType borderType )
58
+ => borderType switch
59
+ {
60
+ ImageBorderType . Const => BorderTypes . Constant ,
61
+ ImageBorderType . Repl => BorderTypes . Replicate ,
62
+ ImageBorderType . Wrap => BorderTypes . Wrap ,
63
+ ImageBorderType . Mirror => BorderTypes . Reflect ,
64
+ _ => throw new NotSupportedException ( $ "Border type { borderType } is not supported.")
65
+ } ;
66
+
67
+ private static GCHandleDiposable ToMat ( this Array data , V2l size , V2l delta , long firstIndex , MatType matType , int elementSize , out CvMat result )
44
68
{
45
- { ImageInterpolation . Near , ( InterpolationFlags ) 6 } , // INTER_NEAREST_EXACT
46
- { ImageInterpolation . Linear , InterpolationFlags . Linear } ,
47
- { ImageInterpolation . Cubic , InterpolationFlags . Cubic } ,
48
- { ImageInterpolation . Lanczos , InterpolationFlags . Lanczos4 } ,
49
- } ;
69
+ var gc = data . Pin ( ) ;
50
70
51
- public static InterpolationFlags ToInterpolationFlags ( this ImageInterpolation interpolation )
52
- {
53
- if ( interpolationFlags . TryGetValue ( interpolation , out InterpolationFlags flags ) ) return flags ;
54
- else throw new NotSupportedException ( $ "Filter { interpolation } is not supported.") ;
71
+ var ptr = IntPtr . Add ( gc . AddrOfPinnedObject ( ) , ( int ) firstIndex * elementSize ) ;
72
+ var sizei = size . ToV2i ( ) ;
73
+ var deltai = delta . YX * elementSize ;
74
+
75
+ result = CvMat . FromPixelData ( sizei . YX . ToArray ( ) , matType , ptr , deltai . ToArray ( ) ) ;
76
+ return gc ;
55
77
}
78
+
79
+ public static GCHandleDiposable ToMat < T > ( this Matrix < T > matrix , MatType matType , int elementSize , out CvMat result )
80
+ => matrix . Data . ToMat ( matrix . Size , matrix . Delta , matrix . FirstIndex , matType , elementSize , out result ) ;
81
+
82
+ public static GCHandleDiposable ToMat < T > ( this Volume < T > volume , MatType matType , int elementSize , out CvMat result )
83
+ => volume . Data . ToMat ( volume . Size . XY , volume . Delta . XY , volume . FirstIndex , matType , elementSize , out result ) ;
56
84
}
57
85
86
+ #endregion
87
+
58
88
public sealed class PixProcessor : IPixProcessor
59
89
{
60
90
public string Name => "OpenCV" ;
61
91
62
- public PixProcessorCaps Capabilities => PixProcessorCaps . Scale ;
92
+ public PixProcessorCaps Capabilities => PixProcessorCaps . Scale | PixProcessorCaps . Remap ;
63
93
64
94
[ OnAardvarkInit ]
65
95
public static void Init ( )
66
96
{
67
97
PixImage . AddProcessor ( Instance ) ;
68
98
}
69
99
100
+ #region Scale
101
+
70
102
public PixImage < T > Scale < T > ( PixImage < T > image , V2d scaleFactor , ImageInterpolation interpolation )
71
103
{
72
104
var src = image . Volume ;
@@ -84,34 +116,88 @@ public PixImage<T> Scale<T>(PixImage<T> image, V2d scaleFactor, ImageInterpolati
84
116
85
117
var dst = newSize . CreateImageVolume < T > ( ) ;
86
118
87
- var matType = typeof ( T ) . ToMatType ( ( int ) src . SZ ) ;
119
+ var matType = typeof ( T ) . ToMatType ( image . ChannelCount ) ;
88
120
var elementSize = typeof ( T ) . GetCLRSize ( ) ;
89
121
90
- using var srcGC = src . Data . Pin ( ) ;
91
- var srcPtr = IntPtr . Add ( srcGC . AddrOfPinnedObject ( ) , ( int ) src . FirstIndex * elementSize ) ;
92
- var srcSize = src . Size . XY . ToV2i ( ) ;
93
- var srcDelta = src . Delta . YX * elementSize ;
94
-
95
- using var dstGC = dst . Data . Pin ( ) ;
96
- var dstPtr = dstGC . AddrOfPinnedObject ( ) ;
97
- var dstSize = dst . Size . XY . ToV2i ( ) ;
122
+ using var _src = src . ToMat ( matType , elementSize , out var srcMat ) ;
123
+ using var _dst = dst . ToMat ( matType , elementSize , out var dstMat ) ;
98
124
99
- var srcMat = CvMat . FromPixelData ( srcSize . YX . ToArray ( ) , matType , srcPtr , srcDelta . ToArray ( ) ) ;
100
- var dstMat = CvMat . FromPixelData ( dstSize . Y , dstSize . X , matType , dstPtr ) ;
101
- Cv2 . Resize ( srcMat , dstMat , new Size ( dstSize . X , dstSize . Y ) , interpolation : interpolation . ToInterpolationFlags ( ) ) ;
125
+ Cv2 . Resize (
126
+ srcMat , dstMat ,
127
+ new Size ( ( int ) dst . SX , ( int ) dst . SY ) ,
128
+ interpolation : interpolation . ToInterpolationFlags ( true )
129
+ ) ;
102
130
103
131
return new ( image . Format , dst ) ;
104
132
}
105
133
134
+ #endregion
135
+
136
+ #region Rotate
137
+
106
138
public PixImage < T > Rotate < T > ( PixImage < T > image , double angleInRadians , bool resize , ImageInterpolation interpolation ,
107
139
ImageBorderType borderType = ImageBorderType . Const ,
108
140
T border = default )
109
141
=> null ;
110
142
143
+ #endregion
144
+
145
+ #region Remap
146
+
147
+ // TODO: Change the interface to accept T[] as border value
148
+ /// <inheritdoc cref="Remap{T}(PixImage{T}, Matrix{float}, Matrix{float}, ImageInterpolation, ImageBorderType, T)"/>
111
149
public PixImage < T > Remap < T > ( PixImage < T > image , Matrix < float > mapX , Matrix < float > mapY , ImageInterpolation interpolation ,
112
150
ImageBorderType borderType = ImageBorderType . Const ,
113
- T border = default )
114
- => null ;
151
+ T [ ] border = default )
152
+ {
153
+ var src = image . Volume ;
154
+
155
+ if ( ! src . HasImageWindowLayout ( ) )
156
+ {
157
+ throw new ArgumentException ( $ "Volume must be in image layout (Delta = { src . Delta } ).") ;
158
+ }
159
+
160
+ if ( mapX . Size != mapY . Size )
161
+ {
162
+ throw new ArgumentException ( $ "Size of coordinate maps must match (mapX: { mapX . Size } , mapY: { mapY . Size } ).") ;
163
+ }
164
+
165
+ var matType = typeof ( T ) . ToMatType ( image . ChannelCount ) ;
166
+ var elementSize = typeof ( T ) . GetCLRSize ( ) ;
167
+
168
+ var dstSize = new V3l ( mapX . Size , image . ChannelCountL ) ;
169
+ var dst = dstSize . CreateImageVolume < T > ( ) ;
170
+
171
+ using var _s = src . ToMat ( matType , elementSize , out var srcMat ) ;
172
+ using var _d = dst . ToMat ( matType , elementSize , out var dstMat ) ;
173
+ using var _x = mapX . ToMat ( MatType . CV_32FC1 , 4 , out var mapXMat ) ;
174
+ using var _y = mapY . ToMat ( MatType . CV_32FC1 , 4 , out var mapYMat ) ;
175
+
176
+ Scalar borderValue = new ( ) ;
177
+ if ( borderType == ImageBorderType . Const && border != null )
178
+ {
179
+ var order = image . Format . ChannelOrder ( ) ;
180
+
181
+ for ( var i = 0 ; i < Fun . Min ( border . Length , 4 ) ; i ++ )
182
+ borderValue [ i ] = Convert . ToDouble ( border [ order [ i ] ] ) ;
183
+ }
184
+
185
+ Cv2 . Remap (
186
+ srcMat , dstMat , mapXMat , mapYMat ,
187
+ interpolation . ToInterpolationFlags ( false ) ,
188
+ borderType . ToBorderTypes ( ) ,
189
+ borderValue
190
+ ) ;
191
+
192
+ return new ( image . Format , dst ) ;
193
+ }
194
+
195
+ public PixImage < T > Remap < T > ( PixImage < T > image , Matrix < float > mapX , Matrix < float > mapY , ImageInterpolation interpolation ,
196
+ ImageBorderType borderType ,
197
+ T border )
198
+ => Remap ( image , mapX , mapY , interpolation , borderType , new T [ ] { border , border , border , border } ) ;
199
+
200
+ #endregion
115
201
116
202
private PixProcessor ( ) { }
117
203
0 commit comments