@@ -1552,6 +1552,7 @@ public Mat Row(int y)
15521552 ThrowIfDisposed ( ) ;
15531553 NativeMethods . HandleException (
15541554 NativeMethods . core_Mat_row ( CvPtr , y , out var matPtr ) ) ;
1555+ GC . KeepAlive ( this ) ;
15551556 return new Mat ( matPtr ) ;
15561557 }
15571558
@@ -3118,6 +3119,8 @@ public Mat EmptyClone()
31183119 /// </summary>
31193120 /// <typeparam name="T"></typeparam>
31203121 /// <returns></returns>
3122+ [ Obsolete ( "Use At<T>(row, col) for occasional access, or AsRows<T>() for high-performance loops. " +
3123+ "GetGenericIndexer uses Marshal.PtrToStructure which is slower than both alternatives." ) ]
31213124 public Indexer < T > GetGenericIndexer < T > ( ) where T : struct
31223125 {
31233126 return new Indexer < T > ( this ) ;
@@ -3136,6 +3139,8 @@ public UnsafeIndexer<T> GetUnsafeGenericIndexer<T>() where T : unmanaged
31363139 /// Mat Indexer
31373140 /// </summary>
31383141 /// <typeparam name="T"></typeparam>
3142+ [ Obsolete ( "Use At<T>(row, col) for occasional access, or AsRows<T>() for high-performance loops. " +
3143+ "This class uses Marshal.PtrToStructure which is slower than both alternatives." ) ]
31393144 public sealed class Indexer < T > : MatIndexer < T > where T : struct
31403145 {
31413146 private readonly long ptrVal ;
@@ -3401,13 +3406,23 @@ public T Get<T>(params int[] idx) where T : struct
34013406 }
34023407
34033408 /// <summary>
3404- /// Returns a value to the specified array element.
3409+ /// Returns a reference to the specified array element.
3410+ /// For 2D matrices, <paramref name="i0"/> is the row index (dimension 0).
3411+ /// Do NOT call this with a column index on a row-submatrix obtained from <see cref="Row"/>;
3412+ /// use <see cref="At{T}(int, int)"/> or <see cref="RowSpan{T}"/> instead.
3413+ /// For performance-sensitive pixel loops, prefer <see cref="AsRows{T}"/>.
34053414 /// </summary>
34063415 /// <typeparam name="T"></typeparam>
34073416 /// <param name="i0">Index along the dimension 0</param>
3408- /// <returns>A value to the specified array element.</returns>
3417+ /// <returns>A reference to the specified array element.</returns>
34093418 public unsafe ref T At < T > ( int i0 ) where T : unmanaged
34103419 {
3420+ #if DEBUG
3421+ if ( Dims == 2 && Rows == 1 && Cols > 1 )
3422+ throw new InvalidOperationException (
3423+ "At<T>(int) on a 1-row 2D matrix treats i0 as a row index, not a column index. " +
3424+ "Use At<T>(0, col) or RowSpan<T>(0) instead." ) ;
3425+ #endif
34113426 var p = Ptr ( i0 ) ;
34123427 return ref Unsafe . AsRef < T > ( p . ToPointer ( ) ) ;
34133428 }
@@ -4241,12 +4256,49 @@ public void ForEachAsVec6d(MatForeachFunctionVec6d operation)
42414256
42424257 #endregion
42434258
4259+ /// <summary>
4260+ /// Returns a <see cref="Span{T}"/> over a single row of this matrix without allocating a submatrix object.
4261+ /// Padding bytes between rows are excluded from the span.
4262+ /// For iterating all rows in a loop, prefer <see cref="AsRows{T}"/> which captures the step once.
4263+ /// </summary>
4264+ /// <typeparam name="T">Element type. Must match the matrix element type.</typeparam>
4265+ /// <param name="row">Zero-based row index.</param>
4266+ /// <returns>A span covering the <paramref name="row"/>-th row.</returns>
4267+ public unsafe Span < T > RowSpan < T > ( int row ) where T : unmanaged
4268+ {
4269+ ThrowIfDisposed ( ) ;
4270+ if ( Dims != 2 )
4271+ throw new InvalidOperationException ( "RowSpan is only supported for 2D matrices." ) ;
4272+ if ( ( uint ) row >= ( uint ) Rows )
4273+ throw new ArgumentOutOfRangeException ( nameof ( row ) ) ;
4274+ var rowPtr = DataPointer + ( nint ) Step ( 0 ) * row ;
4275+ return new Span < T > ( rowPtr , Cols * ElemSize ( ) / sizeof ( T ) ) ;
4276+ }
4277+
4278+ /// <summary>
4279+ /// Returns a <see cref="MatRowAccessor{T}"/> that provides efficient row-by-row access
4280+ /// with no P/Invoke per row or per element.
4281+ /// The data pointer, step, and dimensions are captured once; all indexing is pure pointer arithmetic.
4282+ /// </summary>
4283+ /// <typeparam name="T">Element type. Must match the matrix element type (e.g. <see cref="Vec3b"/> for CV_8UC3).</typeparam>
4284+ /// <returns>A <see cref="MatRowAccessor{T}"/> over this matrix.</returns>
4285+ /// <exception cref="InvalidOperationException">Thrown when the matrix is not 2-dimensional.</exception>
4286+ public unsafe MatRowAccessor < T > AsRows < T > ( ) where T : unmanaged
4287+ {
4288+ ThrowIfDisposed ( ) ;
4289+ if ( Dims != 2 )
4290+ throw new InvalidOperationException ( "AsRows is only supported for 2D matrices." ) ;
4291+ var elemCount = Cols * ElemSize ( ) / sizeof ( T ) ;
4292+ return new MatRowAccessor < T > ( ( nint ) DataPointer , ( nint ) Step ( 0 ) , Rows , elemCount ) ;
4293+ }
4294+
42444295 /// <summary>
42454296 /// Creates a new span over the Mat.
4297+ /// The matrix must be continuous (<see cref="IsContinuous"/>); returns an empty span otherwise.
42464298 /// </summary>
42474299 /// <typeparam name="T"></typeparam>
42484300 /// <returns></returns>
4249- public unsafe Span < T > AsSpan < T > ( ) where T : unmanaged
4301+ public unsafe Span < T > AsSpan < T > ( ) where T : unmanaged
42504302 => IsContinuous ( ) ? new Span < T > ( DataPointer , ( int ) Total ( ) * ElemSize ( ) / sizeof ( T ) ) : [ ] ;
42514303
42524304 #endregion
0 commit comments