The Mavic 3 Multispectral does not give you a stacked file. Each shutter press dumps four 16-bit TIFFs (green, red, red edge and NIR) plus a separate RGB JPEG. Those four MS cameras do not share an optical centre. If you drop the TIFFs into QGIS as a virtual stack and run NDVI, crop rows fringe and rocks double. That is the whole job: get four bands onto one pixel grid, then look at the result as a TIFF.
We followed DJI's own Mavic 3M Image Processing Guide. The code that came out of that is now a public GitHub repo. It is open to changes. This post is the list of things that wasted time before a stacked frame would sit still in QGIS.
What the guide actually asks for
Four steps, in their order. Skip one and the TIFF looks fine until you zoom.
- Vignetting from
VignettingDataand the calibrated optical centre. - Distortion with OpenCV
undistort()andDewarpData. Add the vignette centre tocxandcy. Do not feednewcameramtxin. DJI is blunt about that. -
CalibratedHMatrixthroughwarpPerspective(). That maps each physical band onto the designed plane. DJI says that is enough in hover. - Residual shift from different exposure times. ECC on edges, or SIFT/AKAZE. We have not shipped this. Mapping grids at speed still show a few pixels of crawl on hard edges.
NDVI in that PDF is not (NIR-R)/(NIR+R) on raw digital numbers. It uses black level, gain, exposure and the sun-sensor Irradiance tag (Eq. 6). Our --indices TIFFs are the simple ratio so you can see if bands line up. They are not a reflectance product.
The issues we actually hit
The files are not a stack. Group *_MS_G.TIF, *_MS_R.TIF, *_MS_RE.TIF and *_MS_NIR.TIF by capture prefix. One missing band and you get a half set. The RGB JPEG is a different camera. Leave it out.
Colab plus Drive was a dead end for sharing. The working notebook pointed at /content/MultiSample and a personal Drive folder. The public repo takes a local folder and nothing else.
QGIS shows a black rectangle. These are uint16. Until you stretch MinMax (or a cumulative cut) in Layer Properties, the canvas looks empty. We lost more time on that than on the H-matrix.
Band 1 is NIR. The stacked file is NIR, Green, Red, RedEdge. Identify a pixel and Band 1 is not red. False colour (NIR as red) is Red = Band 1, Green = Band 2, Blue = Band 3. If vegetation is not red, you have the bands swapped, not a dead crop.
No map. Rasterio warns there is no geotransform. QGIS parks the raster at 0,0 or treats it as a non-spatial image. A single frame is not an orthomosaic. GPS from XMP is copied into TIFF tags so you can read lat/long. It will not snap to the basemap. Stitch in Terra, Metashape or Pix4D for that.
Warp leaves empty edges. We crop 50 pixels after stacking. Too little and QGIS still shows a halo. Too much and you shave real crop. Writing BLOCKXSIZE without TILED=YES also throws. The public writer sets tiled 256 and LZW.
Hover versus a grid. H-matrix is the hover method. A mapping line at speed still needs step 4. If Green and Red disagree at a fence post at 50% opacity, that is residual shift, not a bad vignette polynomial.
How we review a frame in QGIS now
Load one raw *_MS_NIR.TIF and stretch it. Confirm the paddock is there. Load {capture}_aligned.tif. Same stretch. Multiband colour as above. Toggle 50% opacity against the raw green band. Raster Calculator if you want a DN NDVI: ("stack@1" - "stack@3") / ("stack@1" + "stack@3"), stretch about -0.2 to 0.8. Rainbow edges mean alignment is still off. Then stop. This is a frame check, not a map.
The install line and QGIS notes live in the m3m-image-stacking repo. If your grid still crawls after the H-matrix, or you have a clean Eq. 6 sun-sensor patch, send a pull request.
FAQ
Can I skip this and process in DJI Terra?
Yes. Terra's multispectral project type is the supported stitch. This stacker is for looking at one capture in QGIS before you commit a block, or for a pipeline that is not Terra.
Why does my stacked TIFF sit at 0,0?
The file has no CRS or geotransform. That is expected. Use it as an image. Do not georeference a single frame and call it a map.
Is the NDVI from --indices the same as the DJI formula?
No. It is (NIR-R)/(NIR+R) on digital numbers. Eq. 6 in the Image Processing Guide is the radiometric version. We will take that patch.
Talk through the job if you are wiring M3M frames into a GIS pipeline we have not seen yet. Spray aircraft are a different brand. Sensors hub: payloads. Processing context: Terra vs Modify.
Read next: drone data pipeline · AUSCORS NTRIP
