0

I'm using C++ (QtCreator) QGIS 2.0 und openCV2 on an 64 bit Workstation running Debian Wheezy. The Application I try to assemble is a standalone QGIS one and will be a mix of gis and image processing software.

Problem description:

I've a QgsMapLayerCanvas with an associated QgsRasterlayer based on an GeoTiff with UTM32 CRS and a resolution of 2 cm. My objective ist to point on an location, determin the pixel data and cut out the data buffer in a 2 x 2 meter window . In the next step this buffer should go to an opencv image processing routine. I' havent found a ready to use solution in the qgis library.

My guess is, that the QgsRasterDataProvider can do this job but. But I cannot find any useful snippets in the web for this task.

Is there somebody who has experience with this matter?


Here the snippet of my first try:

void MainWindow::doMapImgCanvasClicked(const QgsPoint &point,
                                  Qt::MouseButton button) {


    if (!(qgsMapImgLayer && qgsMapImgProvider) ) return;

    // Size of the window for the image process
    int winWidth  = 10; int winHeight = 10;

    // Calculate the pixel position
    QPoint pixPos(-1,-1);
    doMapImgCalcRasterPos(point, qgsMapImgLayer, pixPos);

    // Give me a response for coords and pixel pos 
    QString str;
    str.sprintf("COORD %f %f PIX %d %d", 
                       point.x(), point.y(),
           pixPos.x(), pixPos.y());
    outLog(str);

    // Create a region of interest
    QgsRectangle roi(point.x()-1, point.y()-1, point.x()+1, point.y()+1);
                // Make a copy of Data 2x2 m for the first band
    QgsRasterBlock *block = qgsMapImgProvider->block(
      1, roi, winWidth, winHeight);

     // Block data is OK?
    if (block->isValid()) { 
        outLog("VALID");
    }

                // Blockdata empty?
    if (block->isEmpty()) { 
      outLog("EMPTY");
    } else { 
     return;
    }

    // Is this the buffer?   
    char* bits = block->bits();
    str.sprintf("DB.TYPE %d", block->dataType()); outLog(str);

    // OK This is the size of the Pointer 
    str.sprintf("DB.NUM %d", sizeof(bits) ); outLog(str);

    // Test Output
    for (int i=0; i<winWidth*winHeight; i++) {
            char c = bits[i];
        str.sprintf("PIX[%d]=%d", i, bits[i] ); outLog(str);
    }
}
0

I found this solution:

/** Conversation of a QGIS RasterLayer data block to a OpenCV Matrix.
 *
 * Remarks:
 *   Only 3 channel byte ased raster data are accepted.
 *
 * @param point - Center position of the patch
 * @param radius - How many meters around the center position we interested
 * @param width  - Width of the CV::Mat
 * @param height  - Height of the CV::Mat
 *
 * @returns an OperationCode
 *   1 OK, the CV object is the member Variable cv::Mat *cvImageBird;
 * -10 raster data provider is empty
 * -20 less or more than 3 channels
 * -30 raster data are not byte based
 * -110 raster data are not byte based at the 1. band
 * -120 raster data are not byte based at the 2. band
 * -130 raster data are not byte based at the 3. band
 * -(2|3|4)10 raster data block invalid at the 1. band
 * -(2|3|4)20 raster data block invalid at the 2. band
 * -(2|3|4)30 raster data block invalid at the 3. band
 *     -2?0  block is valid?
 *     -3?0  block is empty?
 *     -4?0  data bits are empty?
 */
int CnsMapCanvas::mapImg2CV( const QgsPoint& point,
                             double radius, int width, int height) {

    // RasteDataProvider is valid?
    if ( !qgsProvider) return -10; //error code -10

    // Do we have a 3 channels?
    int numBand   = qgsProvider->bandCount();
    if (numBand != 3) return -20;  //error code -20

    // Do we have a byte based sampling?
    QGis::DataType dataType  = qgsProvider->dataType(1);
    if (dataType != QGis::Byte) return -30; //error code -23

    // OK we have a RGB Image!
    // Create the region of interest
    QgsRectangle roi(point.x()-radius, point.y()-radius,
                     point.x()+radius, point.y()+radius);

    // OpenCV member Variable cv::Mat *cvImageBird;
    // free mem if the OPenCV image is assigned
    if (cvImageBird) delete cvImageBird;

    // Create a new on RGB
    cvImageBird = new cv::Mat3b(width, height, CV_8UC3);

    // Iterate over the bands
    for (int band = 0; band < numBand; ++band) {

        // Request data band homogenity?
        if (dataType != qgsProvider->dataType(band+1)) {
             return -100*(band+1)-10; // error codes -110, -120, -130
        }

        // Get the a proper raster block
        QgsRasterBlock *block = qgsProvider->block(band+1, roi, width, height);
        if (!block->isValid()) {
             return -200*(band+1)-10; // error codes -210, -220, -230
        }

        if (block->isEmpty())  {
             return -400*(band+1)-10; // error codes -310, -320, -330
        }

        // Get the data of the raster block
        char *bits = block->bits();
        if (! bits )  {
            return -400*(band+1)-10; // error codes -410, -420, -430
        }

        // Copy the data block into the CV Object
        for (int col=0; col<width; col++) {
            for (int row=0; row<height; row++) {
                cvImageBird->at<cv::Vec3b>(col,row)[band] = *bits;
                bits++;
            }
        }

        // Free mem the qgsDataBlock
        delete block;
    } // eof for(int band...)

    // set a flag, that we have a proper result;
    return 1;
} // eof mapImg2CV(...)
  • Use GDAL or scikit-image – gene Oct 12 '14 at 16:59
  • Hm, the link scikit-image is dead?! But opencv 3.0 can handle GDAL stuff directly..... – huckfinn Jan 24 '15 at 6:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.