Esempio n. 1
0
static void
splitbox(Colorbox* ptr, const int* histogram,
         const HashHistogram* psHashHistogram,
         int nCLevels,
         Colorbox **pfreeboxes, Colorbox **pusedboxes,
         GByte* pabyRedBand,
         GByte* pabyGreenBand,
         GByte* pabyBlueBand, int nPixels)
{
    int		hist2[256];
    int		first=0, last=0;
    Colorbox	*new_cb;
    const int	*iptr;
    int *histp;
    int	i, j;
    int	ir,ig,ib;
    int sum, sum1, sum2;
    enum { RED, GREEN, BLUE } axis;

    /*
     * See which axis is the largest, do a histogram along that
     * axis.  Split at median point.  Contract both new boxes to
     * fit points and return
     */
    i = ptr->rmax - ptr->rmin;
    if (i >= ptr->gmax - ptr->gmin  && i >= ptr->bmax - ptr->bmin)
        axis = RED;
    else if (ptr->gmax - ptr->gmin >= ptr->bmax - ptr->bmin)
        axis = GREEN;
    else
        axis = BLUE;
    /* get histogram along longest axis */
    int nIters = (ptr->rmax - ptr->rmin + 1) * (ptr->gmax - ptr->gmin + 1) *
                 (ptr->bmax - ptr->bmin + 1);
    //printf("nIters = %d\n", nIters);
    switch (axis) {
    case RED:
    {
        if( nPixels != 0 && nIters > nPixels )
        {
            memset(hist2, 0, sizeof(hist2));
            const int           rmin = ptr->rmin,
                                rmax = ptr->rmax,
                                gmin = ptr->gmin,
                                gmax = ptr->gmax,
                                bmin = ptr->bmin,
                                bmax = ptr->bmax;
            for(int i=0; i<nPixels; i++)
            {
                int iR = pabyRedBand[i];
                int iG = pabyGreenBand[i];
                int iB = pabyBlueBand[i];
                if( iR >= rmin && iR <= rmax &&
                        iG >= gmin && iG <= gmax &&
                        iB >= bmin && iB <= bmax )
                {
                    hist2[iR] ++;
                }
            }
        }
        else if( psHashHistogram )
        {
            histp = &hist2[ptr->rmin];
            for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
                *histp = 0;
                for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
                    for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
                    {
                        *histp += FindColorCount(psHashHistogram,
                                                 MAKE_COLOR_CODE(ir, ig, ib));
                    }
                }
                histp++;
            }
        }
        else
        {
            histp = &hist2[ptr->rmin];
            for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
                *histp = 0;
                for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
                    iptr = &HISTOGRAM(histogram,nCLevels,ir,ig,ptr->bmin);
                    for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
                        *histp += *iptr++;
                }
                histp++;
            }
        }
        first = ptr->rmin;
        last = ptr->rmax;
        break;
    }
    case GREEN:
    {
        if( nPixels != 0 && nIters > nPixels )
        {
            memset(hist2, 0, sizeof(hist2));
            const int           rmin = ptr->rmin,
                                rmax = ptr->rmax,
                                gmin = ptr->gmin,
                                gmax = ptr->gmax,
                                bmin = ptr->bmin,
                                bmax = ptr->bmax;
            for(int i=0; i<nPixels; i++)
            {
                int iR = pabyRedBand[i];
                int iG = pabyGreenBand[i];
                int iB = pabyBlueBand[i];
                if( iR >= rmin && iR <= rmax &&
                        iG >= gmin && iG <= gmax &&
                        iB >= bmin && iB <= bmax )
                {
                    hist2[iG] ++;
                }
            }
        }
        else if( psHashHistogram )
        {
            histp = &hist2[ptr->gmin];
            for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
                *histp = 0;
                for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
                    for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
                    {
                        *histp += FindColorCount(psHashHistogram,
                                                 MAKE_COLOR_CODE(ir, ig, ib));
                    }
                }
                histp++;
            }
        }
        else
        {
            histp = &hist2[ptr->gmin];
            for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
                *histp = 0;
                for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
                    iptr = &HISTOGRAM(histogram,nCLevels,ir,ig,ptr->bmin);
                    for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
                        *histp += *iptr++;
                }
                histp++;
            }
        }
        first = ptr->gmin;
        last = ptr->gmax;
        break;
    }
    case BLUE:
    {
        if( nPixels != 0 && nIters > nPixels )
        {
            memset(hist2, 0, sizeof(hist2));
            const int           rmin = ptr->rmin,
                                rmax = ptr->rmax,
                                gmin = ptr->gmin,
                                gmax = ptr->gmax,
                                bmin = ptr->bmin,
                                bmax = ptr->bmax;
            for(int i=0; i<nPixels; i++)
            {
                int iR = pabyRedBand[i];
                int iG = pabyGreenBand[i];
                int iB = pabyBlueBand[i];
                if( iR >= rmin && iR <= rmax &&
                        iG >= gmin && iG <= gmax &&
                        iB >= bmin && iB <= bmax )
                {
                    hist2[iB] ++;
                }
            }
        }
        else if( psHashHistogram )
        {
            histp = &hist2[ptr->bmin];
            for (ib = ptr->bmin; ib <= ptr->bmax; ++ib) {
                *histp = 0;
                for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
                    for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
                        *histp += FindColorCount(psHashHistogram,
                                                 MAKE_COLOR_CODE(ir, ig, ib));
                    }
                }
                histp++;
            }
        }
        else
        {
            histp = &hist2[ptr->bmin];
            for (ib = ptr->bmin; ib <= ptr->bmax; ++ib) {
                *histp = 0;
                for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
                    iptr = &HISTOGRAM(histogram,nCLevels,ir,ptr->gmin,ib);
                    for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
                        *histp += *iptr;
                        iptr += nCLevels;
                    }
                }
                histp++;
            }
        }
        first = ptr->bmin;
        last = ptr->bmax;
        break;
    }
    }
    /* find median point */
    sum2 = ptr->total / 2;
    histp = &hist2[first];
    sum = 0;
    for (i = first; i <= last && (sum += *histp++) < sum2; ++i)
        ;
    if (i == first)
        i++;

    /* Create new box, re-allocate points */
    new_cb = *pfreeboxes;
    *pfreeboxes = new_cb->next;
    if (*pfreeboxes)
        (*pfreeboxes)->prev = NULL;
    if (*pusedboxes)
        (*pusedboxes)->prev = new_cb;
    new_cb->next = *pusedboxes;
    *pusedboxes = new_cb;

    histp = &hist2[first];
    for (sum1 = 0, j = first; j < i; j++)
        sum1 += *histp++;
    for (sum2 = 0, j = i; j <= last; j++)
        sum2 += *histp++;
    new_cb->total = sum1;
    ptr->total = sum2;

    new_cb->rmin = ptr->rmin;
    new_cb->rmax = ptr->rmax;
    new_cb->gmin = ptr->gmin;
    new_cb->gmax = ptr->gmax;
    new_cb->bmin = ptr->bmin;
    new_cb->bmax = ptr->bmax;
    switch (axis) {
    case RED:
        new_cb->rmax = i-1;
        ptr->rmin = i;
        break;
    case GREEN:
        new_cb->gmax = i-1;
        ptr->gmin = i;
        break;
    case BLUE:
        new_cb->bmax = i-1;
        ptr->bmin = i;
        break;
    }
    if( nPixels != 0 &&
            (new_cb->rmax - new_cb->rmin + 1) * (new_cb->gmax - new_cb->gmin + 1) *
            (new_cb->bmax - new_cb->bmin + 1) > nPixels )
    {
        shrinkboxFromBand(new_cb, pabyRedBand, pabyGreenBand, pabyBlueBand, nPixels);
    }
    else if( psHashHistogram != NULL )
    {
        shrinkboxFromHashHistogram(new_cb, psHashHistogram);
    }
    else
    {
        shrinkbox(new_cb, histogram, nCLevels);
    }
    if( nPixels != 0 &&
            (ptr->rmax - ptr->rmin + 1) * (ptr->gmax - ptr->gmin + 1) *
            (ptr->bmax - ptr->bmin + 1) > nPixels )
    {
        shrinkboxFromBand(ptr, pabyRedBand, pabyGreenBand, pabyBlueBand, nPixels);
    }
    else if( psHashHistogram != NULL )
    {
        shrinkboxFromHashHistogram(ptr, psHashHistogram);
    }
    else
    {
        shrinkbox(ptr, histogram, nCLevels);
    }
}
Esempio n. 2
0
int
GDALComputeMedianCutPCTInternal( GDALRasterBandH hRed,
                                 GDALRasterBandH hGreen,
                                 GDALRasterBandH hBlue,
                                 GByte* pabyRedBand,
                                 GByte* pabyGreenBand,
                                 GByte* pabyBlueBand,
                                 int (*pfnIncludePixel)(int,int,void*),
                                 int nColors,
                                 int nBits,
                                 int* panHistogram, /* NULL, or at least of size (1<<nBits)^3 * sizeof(int) bytes */
                                 GDALColorTableH hColorTable,
                                 GDALProgressFunc pfnProgress,
                                 void * pProgressArg )

{
    VALIDATE_POINTER1( hRed, "GDALComputeMedianCutPCT", CE_Failure );
    VALIDATE_POINTER1( hGreen, "GDALComputeMedianCutPCT", CE_Failure );
    VALIDATE_POINTER1( hBlue, "GDALComputeMedianCutPCT", CE_Failure );

    int		nXSize, nYSize;
    CPLErr err = CE_None;

    /* -------------------------------------------------------------------- */
    /*      Validate parameters.                                            */
    /* -------------------------------------------------------------------- */
    nXSize = GDALGetRasterBandXSize( hRed );
    nYSize = GDALGetRasterBandYSize( hRed );

    if( GDALGetRasterBandXSize( hGreen ) != nXSize
            || GDALGetRasterBandYSize( hGreen ) != nYSize
            || GDALGetRasterBandXSize( hBlue ) != nXSize
            || GDALGetRasterBandYSize( hBlue ) != nYSize )
    {
        CPLError( CE_Failure, CPLE_IllegalArg,
                  "Green or blue band doesn't match size of red band.\n" );

        return CE_Failure;
    }

    if( pfnIncludePixel != NULL )
    {
        CPLError( CE_Failure, CPLE_IllegalArg,
                  "GDALComputeMedianCutPCT() doesn't currently support "
                  " pfnIncludePixel function." );

        return CE_Failure;
    }

    if ( nColors <= 0 )
    {
        CPLError( CE_Failure, CPLE_IllegalArg,
                  "GDALComputeMedianCutPCT() : nColors must be strictly greater than 1." );

        return CE_Failure;
    }

    if ( nColors > 256 )
    {
        CPLError( CE_Failure, CPLE_IllegalArg,
                  "GDALComputeMedianCutPCT() : nColors must be lesser than or equal to 256." );

        return CE_Failure;
    }

    if( pfnProgress == NULL )
        pfnProgress = GDALDummyProgress;

    /* ==================================================================== */
    /*      STEP 1: create empty boxes.                                     */
    /* ==================================================================== */
    int	     i;
    Colorbox *box_list, *ptr;
    int* histogram;
    Colorbox *freeboxes;
    Colorbox *usedboxes;
    int nCLevels = 1 << nBits;
    int nColorShift = 8 - nBits;
    int nColorCounter = 0;
    GByte anRed[256], anGreen[256], anBlue[256];
    int nPixels = 0;
    HashHistogram* psHashHistogram = NULL;

    if( nBits == 8 && pabyRedBand != NULL && pabyGreenBand != NULL &&
            pabyBlueBand != NULL && nXSize < INT_MAX / nYSize )
    {
        nPixels = nXSize * nYSize;
    }

    if( panHistogram )
    {
        if( nBits == 8 && (GIntBig)nXSize * nYSize <= 65536 )
        {
            /* If the image is small enough, then the number of colors */
            /* will be limited and using a hashmap, rather than a full table */
            /* will be more efficient */
            histogram = NULL;
            psHashHistogram = (HashHistogram*)panHistogram;
            memset(psHashHistogram, 0xFF, sizeof(HashHistogram) * PRIME_FOR_65536);
        }
        else
        {
            histogram = panHistogram;
            memset(histogram, 0, nCLevels*nCLevels*nCLevels * sizeof(int));
        }
    }
    else
    {
        histogram = (int*) VSICalloc(nCLevels*nCLevels*nCLevels,sizeof(int));
        if( histogram == NULL )
        {
            CPLError( CE_Failure, CPLE_OutOfMemory,
                      "VSICalloc(): Out of memory in GDALComputeMedianCutPCT" );
            return CE_Failure;
        }
    }
    usedboxes = NULL;
    box_list = freeboxes = (Colorbox *)CPLMalloc(nColors*sizeof (Colorbox));
    freeboxes[0].next = &freeboxes[1];
    freeboxes[0].prev = NULL;
    for (i = 1; i < nColors-1; ++i) {
        freeboxes[i].next = &freeboxes[i+1];
        freeboxes[i].prev = &freeboxes[i-1];
    }
    freeboxes[nColors-1].next = NULL;
    freeboxes[nColors-1].prev = &freeboxes[nColors-2];

    /* ==================================================================== */
    /*      Build histogram.                                                */
    /* ==================================================================== */
    GByte	*pabyRedLine, *pabyGreenLine, *pabyBlueLine;
    int		iLine, iPixel;

    /* -------------------------------------------------------------------- */
    /*      Initialize the box datastructures.                              */
    /* -------------------------------------------------------------------- */
    ptr = freeboxes;
    freeboxes = ptr->next;
    if (freeboxes)
        freeboxes->prev = NULL;
    ptr->next = usedboxes;
    usedboxes = ptr;
    if (ptr->next)
        ptr->next->prev = ptr;

    ptr->rmin = ptr->gmin = ptr->bmin = 999;
    ptr->rmax = ptr->gmax = ptr->bmax = -1;
    ptr->total = nXSize * nYSize;

    /* -------------------------------------------------------------------- */
    /*      Collect histogram.                                              */
    /* -------------------------------------------------------------------- */
    pabyRedLine = (GByte *) VSIMalloc(nXSize);
    pabyGreenLine = (GByte *) VSIMalloc(nXSize);
    pabyBlueLine = (GByte *) VSIMalloc(nXSize);

    if (pabyRedLine == NULL ||
            pabyGreenLine == NULL ||
            pabyBlueLine == NULL)
    {
        CPLError( CE_Failure, CPLE_OutOfMemory,
                  "VSIMalloc(): Out of memory in GDALComputeMedianCutPCT" );
        err = CE_Failure;
        goto end_and_cleanup;
    }

    for( iLine = 0; iLine < nYSize; iLine++ )
    {
        if( !pfnProgress( iLine / (double) nYSize,
                          "Generating Histogram", pProgressArg ) )
        {
            CPLError( CE_Failure, CPLE_UserInterrupt, "User Terminated" );
            err = CE_Failure;
            goto end_and_cleanup;
        }

        GDALRasterIO( hRed, GF_Read, 0, iLine, nXSize, 1,
                      pabyRedLine, nXSize, 1, GDT_Byte, 0, 0 );
        GDALRasterIO( hGreen, GF_Read, 0, iLine, nXSize, 1,
                      pabyGreenLine, nXSize, 1, GDT_Byte, 0, 0 );
        GDALRasterIO( hBlue, GF_Read, 0, iLine, nXSize, 1,
                      pabyBlueLine, nXSize, 1, GDT_Byte, 0, 0 );

        for( iPixel = 0; iPixel < nXSize; iPixel++ )
        {
            int	nRed, nGreen, nBlue;

            nRed = pabyRedLine[iPixel] >> nColorShift;
            nGreen = pabyGreenLine[iPixel] >> nColorShift;
            nBlue = pabyBlueLine[iPixel] >> nColorShift;

            ptr->rmin = MIN(ptr->rmin, nRed);
            ptr->gmin = MIN(ptr->gmin, nGreen);
            ptr->bmin = MIN(ptr->bmin, nBlue);
            ptr->rmax = MAX(ptr->rmax, nRed);
            ptr->gmax = MAX(ptr->gmax, nGreen);
            ptr->bmax = MAX(ptr->bmax, nBlue);

            int* pnColor;
            if( psHashHistogram )
            {
                pnColor = FindAndInsertColorCount(psHashHistogram,
                                                  MAKE_COLOR_CODE(nRed, nGreen, nBlue));
            }
            else
            {
                pnColor = &HISTOGRAM(histogram, nCLevels, nRed, nGreen, nBlue);
            }
            if( *pnColor == 0 )
            {
                if( nColorShift == 0 && nColorCounter < nColors )
                {
                    anRed[nColorCounter] = nRed;
                    anGreen[nColorCounter] = nGreen;
                    anBlue[nColorCounter] = nBlue;
                }
                nColorCounter++;
            }
            (*pnColor) ++;
        }
    }

    if( !pfnProgress( 1.0, "Generating Histogram", pProgressArg ) )
    {
        CPLError( CE_Failure, CPLE_UserInterrupt, "User Terminated" );
        err = CE_Failure;
        goto end_and_cleanup;
    }

    if( nColorShift == 0 && nColorCounter <= nColors )
    {
        //CPLDebug("MEDIAN_CUT", "%d colors found <= %d", nColorCounter, nColors);
        for(int iColor = 0; iColor<nColorCounter; iColor++)
        {
            GDALColorEntry  sEntry;
            sEntry.c1 = (GByte) anRed[iColor];
            sEntry.c2 = (GByte) anGreen[iColor];
            sEntry.c3 = (GByte) anBlue[iColor];
            sEntry.c4 = 255;
            GDALSetColorEntry( hColorTable, iColor, &sEntry );
        }
        goto end_and_cleanup;
    }

    /* ==================================================================== */
    /*      STEP 3: continually subdivide boxes until no more free          */
    /*      boxes remain or until all colors assigned.                      */
    /* ==================================================================== */
    while (freeboxes != NULL) {
        ptr = largest_box(usedboxes);
        if (ptr != NULL)
            splitbox(ptr, histogram, psHashHistogram, nCLevels, &freeboxes, &usedboxes,
                     pabyRedBand, pabyGreenBand, pabyBlueBand, nPixels);
        else
            freeboxes = NULL;
    }

    /* ==================================================================== */
    /*      STEP 4: assign colors to all boxes                              */
    /* ==================================================================== */
    for (i = 0, ptr = usedboxes; ptr != NULL; ++i, ptr = ptr->next)
    {
        GDALColorEntry	sEntry;

        sEntry.c1 = (GByte) (((ptr->rmin + ptr->rmax) << nColorShift) / 2);
        sEntry.c2 = (GByte) (((ptr->gmin + ptr->gmax) << nColorShift) / 2);
        sEntry.c3 = (GByte) (((ptr->bmin + ptr->bmax) << nColorShift) / 2);
        sEntry.c4 = 255;
        GDALSetColorEntry( hColorTable, i, &sEntry );
    }

end_and_cleanup:
    CPLFree( pabyRedLine );
    CPLFree( pabyGreenLine );
    CPLFree( pabyBlueLine );

    /* We're done with the boxes now */
    CPLFree(box_list);
    freeboxes = usedboxes = NULL;

    if( panHistogram == NULL )
        CPLFree( histogram );

    return err;
}
Esempio n. 3
0
static void
shrinkbox(Colorbox* box, const int* histogram, int nCLevels)
{
    const int *histp;
    int ir, ig, ib;
    //int count_iter;

    if (box->rmax > box->rmin) {
        //count_iter = 0;
        for (ir = box->rmin; ir <= box->rmax; ++ir) {
            for (ig = box->gmin; ig <= box->gmax; ++ig) {
                histp = &HISTOGRAM(histogram, nCLevels, ir, ig, box->bmin);
                for (ib = box->bmin; ib <= box->bmax; ++ib) {
                    //count_iter ++;
                    if (*histp++ != 0) {
                        //if( count_iter > 65536 ) printf("iter rmin=%d\n", count_iter);
                        box->rmin = ir;
                        goto have_rmin;
                    }
                }
            }
        }
    }
have_rmin:
    if (box->rmax > box->rmin) {
        //count_iter = 0;
        for (ir = box->rmax; ir >= box->rmin; --ir) {
            for (ig = box->gmin; ig <= box->gmax; ++ig) {
                histp = &HISTOGRAM(histogram, nCLevels, ir, ig, box->bmin);
                ib = box->bmin;
                for (; ib <= box->bmax; ++ib) {
                    //count_iter ++;
                    if (*histp++ != 0) {
                        //if( count_iter > 65536 ) printf("iter rmax=%d\n", count_iter);
                        box->rmax = ir;
                        goto have_rmax;
                    }
                }
            }
        }
    }

have_rmax:
    if (box->gmax > box->gmin) {
        //count_iter = 0;
        for (ig = box->gmin; ig <= box->gmax; ++ig) {
            for (ir = box->rmin; ir <= box->rmax; ++ir) {
                histp = &HISTOGRAM(histogram, nCLevels, ir, ig, box->bmin);
                for (ib = box->bmin; ib <= box->bmax; ++ib) {
                    //count_iter ++;
                    if (*histp++ != 0) {
                        //if( count_iter > 65536 ) printf("iter gmin=%d\n", count_iter);
                        box->gmin = ig;
                        goto have_gmin;
                    }
                }
            }
        }
    }

have_gmin:
    if (box->gmax > box->gmin) {
        //count_iter = 0;
        for (ig = box->gmax; ig >= box->gmin; --ig) {
            for (ir = box->rmin; ir <= box->rmax; ++ir) {
                histp = &HISTOGRAM(histogram, nCLevels, ir, ig, box->bmin);
                ib = box->bmin;
                for (; ib <= box->bmax; ++ib) {
                    //count_iter ++;
                    if (*histp++ != 0) {
                        //if( count_iter > 65536 ) printf("iter gmax=%d\n", count_iter);
                        box->gmax = ig;
                        goto have_gmax;
                    }
                }
            }
        }
    }

have_gmax:
    if (box->bmax > box->bmin) {
        //count_iter = 0;
        for (ib = box->bmin; ib <= box->bmax; ++ib) {
            for (ir = box->rmin; ir <= box->rmax; ++ir) {
                histp = &HISTOGRAM(histogram, nCLevels, ir, box->gmin, ib);
                for (ig = box->gmin; ig <= box->gmax; ++ig) {
                    //count_iter ++;
                    if (*histp != 0) {
                        //if( count_iter > 65536 ) printf("iter bmin=%d\n", count_iter);
                        box->bmin = ib;
                        goto have_bmin;
                    }
                    histp += nCLevels;
                }
            }
        }
    }

have_bmin:
    if (box->bmax > box->bmin) {
        //count_iter = 0;
        for (ib = box->bmax; ib >= box->bmin; --ib) {
            for (ir = box->rmin; ir <= box->rmax; ++ir) {
                histp = &HISTOGRAM(histogram, nCLevels, ir, box->gmin, ib);
                ig = box->gmin;
                for (; ig <= box->gmax; ++ig) {
                    //count_iter ++;
                    if (*histp != 0) {
                        //if( count_iter > 65536 ) printf("iter bmax=%d\n", count_iter);
                        box->bmax = ib;
                        goto have_bmax;
                    }
                    histp += nCLevels;
                }
            }
        }
    }

have_bmax:
    ;
}
Esempio n. 4
0
template<class T> static void
splitbox(Colorbox* ptr, const T* histogram,
         const HashHistogram* psHashHistogram,
         int nCLevels,
         Colorbox **pfreeboxes, Colorbox **pusedboxes,
         GByte* pabyRedBand,
         GByte* pabyGreenBand,
         GByte* pabyBlueBand, T nPixels)
{
    T hist2[256] = {};
    int first = 0;
    int last = 0;
    enum { RED, GREEN, BLUE } axis;

    // See which axis is the largest, do a histogram along that axis.  Split at
    // median point.  Contract both new boxes to fit points and return.
    {
        int i = ptr->rmax - ptr->rmin;
        if( i >= ptr->gmax - ptr->gmin  && i >= ptr->bmax - ptr->bmin )
            axis = RED;
        else if( ptr->gmax - ptr->gmin >= ptr->bmax - ptr->bmin )
            axis = GREEN;
        else
            axis = BLUE;
    }
    // Get histogram along longest axis.
    const GUInt32 nIters =
        (ptr->rmax - ptr->rmin + 1) *
        (ptr->gmax - ptr->gmin + 1) *
        (ptr->bmax - ptr->bmin + 1);

    switch( axis )
    {
      case RED:
      {
        if( nPixels != 0 && nIters > nPixels )
        {
            const int rmin = ptr->rmin;
            const int rmax = ptr->rmax;
            const int gmin = ptr->gmin;
            const int gmax = ptr->gmax;
            const int bmin = ptr->bmin;
            const int bmax = ptr->bmax;
            for( T iPixel = 0; iPixel < nPixels; iPixel++ )
            {
                int iR = pabyRedBand[iPixel];
                int iG = pabyGreenBand[iPixel];
                int iB = pabyBlueBand[iPixel];
                if( iR >= rmin && iR <= rmax &&
                    iG >= gmin && iG <= gmax &&
                    iB >= bmin && iB <= bmax )
                {
                    hist2[iR]++;
                }
            }
        }
        else if( psHashHistogram )
        {
            T *histp = &hist2[ptr->rmin];
            for( int ir = ptr->rmin; ir <= ptr->rmax; ++ir )
            {
                *histp = 0;
                for( int ig = ptr->gmin; ig <= ptr->gmax; ++ig )
                {
                    for( int ib = ptr->bmin; ib <= ptr->bmax; ++ib )
                    {
                        *histp += FindColorCount(psHashHistogram,
                                                 MAKE_COLOR_CODE(ir, ig, ib));
                    }
                }
                histp++;
            }
        }
        else
        {
            T *histp = &hist2[ptr->rmin];
            for( int ir = ptr->rmin; ir <= ptr->rmax; ++ir )
            {
                *histp = 0;
                for( int ig = ptr->gmin; ig <= ptr->gmax; ++ig )
                {
                    const T *iptr =
                        HISTOGRAM(histogram, nCLevels, ir, ig, ptr->bmin);
                    for( int ib = ptr->bmin; ib <= ptr->bmax; ++ib )
                        *histp += *iptr++;
                }
                histp++;
            }
        }
        first = ptr->rmin;
        last = ptr->rmax;
        break;
      }
      case GREEN:
      {
        if( nPixels != 0 && nIters > nPixels )
        {
            const int rmin = ptr->rmin;
            const int rmax = ptr->rmax;
            const int gmin = ptr->gmin;
            const int gmax = ptr->gmax;
            const int bmin = ptr->bmin;
            const int bmax = ptr->bmax;
            for( T iPixel = 0; iPixel < nPixels; iPixel++ )
            {
                const int iR = pabyRedBand[iPixel];
                const int iG = pabyGreenBand[iPixel];
                const int iB = pabyBlueBand[iPixel];
                if( iR >= rmin && iR <= rmax &&
                    iG >= gmin && iG <= gmax &&
                    iB >= bmin && iB <= bmax )
                {
                    hist2[iG]++;
                }
            }
        }
        else if( psHashHistogram )
        {
            T *histp = &hist2[ptr->gmin];
            for( int ig = ptr->gmin; ig <= ptr->gmax; ++ig )
            {
                *histp = 0;
                for( int ir = ptr->rmin; ir <= ptr->rmax; ++ir )
                {
                    for( int ib = ptr->bmin; ib <= ptr->bmax; ++ib )
                    {
                        *histp += FindColorCount(psHashHistogram,
                                                 MAKE_COLOR_CODE(ir, ig, ib));
                    }
                }
                histp++;
            }
        }
        else
        {
            T *histp = &hist2[ptr->gmin];
            for( int ig = ptr->gmin; ig <= ptr->gmax; ++ig )
            {
                *histp = 0;
                for( int ir = ptr->rmin; ir <= ptr->rmax; ++ir )
                {
                    const T *iptr =
                        HISTOGRAM(histogram, nCLevels, ir, ig, ptr->bmin);
                    for( int ib = ptr->bmin; ib <= ptr->bmax; ++ib )
                        *histp += *iptr++;
                }
                histp++;
            }
        }
        first = ptr->gmin;
        last = ptr->gmax;
        break;
      }
      case BLUE:
      {
        if( nPixels != 0 && nIters > nPixels )
        {
            const int rmin = ptr->rmin;
            const int rmax = ptr->rmax;
            const int gmin = ptr->gmin;
            const int gmax = ptr->gmax;
            const int bmin = ptr->bmin;
            const int bmax = ptr->bmax;
            for( T iPixel = 0; iPixel < nPixels; iPixel++ )
            {
                const int iR = pabyRedBand[iPixel];
                const int iG = pabyGreenBand[iPixel];
                const int iB = pabyBlueBand[iPixel];
                if( iR >= rmin && iR <= rmax &&
                    iG >= gmin && iG <= gmax &&
                    iB >= bmin && iB <= bmax )
                {
                    hist2[iB]++;
                }
            }
        }
        else if( psHashHistogram )
        {
            T *histp = &hist2[ptr->bmin];
            for( int ib = ptr->bmin; ib <= ptr->bmax; ++ib )
            {
                *histp = 0;
                for( int ir = ptr->rmin; ir <= ptr->rmax; ++ir )
                {
                    for( int ig = ptr->gmin; ig <= ptr->gmax; ++ig )
                    {
                        *histp += FindColorCount(psHashHistogram,
                                                 MAKE_COLOR_CODE(ir, ig, ib));
                    }
                }
                histp++;
            }
        }
        else
        {
            T *histp = &hist2[ptr->bmin];
            for( int ib = ptr->bmin; ib <= ptr->bmax; ++ib )
            {
                *histp = 0;
                for( int ir = ptr->rmin; ir <= ptr->rmax; ++ir )
                {
                    const T *iptr =
                        HISTOGRAM(histogram, nCLevels, ir, ptr->gmin, ib);
                    for( int ig = ptr->gmin; ig <= ptr->gmax; ++ig )
                    {
                        *histp += *iptr;
                        iptr += nCLevels;
                    }
                }
                histp++;
            }
        }
        first = ptr->bmin;
        last = ptr->bmax;
        break;
      }
    }
    // Find median point.
    T *histp = &hist2[first];
    int i = first;  // TODO(schwehr): Rename i.
    {
        T sum = 0;
        T sum2 = static_cast<T>(ptr->total / 2);
        for( ; i <= last && (sum += *histp++) < sum2; ++i )
            {}
    }
    if( i == first )
        i++;

    // Create new box, re-allocate points.
    Colorbox *new_cb = *pfreeboxes;
    *pfreeboxes = new_cb->next;
    if( *pfreeboxes )
        (*pfreeboxes)->prev = NULL;
    if( *pusedboxes )
        (*pusedboxes)->prev = new_cb;
    new_cb->next = *pusedboxes;
    *pusedboxes = new_cb;

    histp = &hist2[first];
    {
        T sum1 = 0;
        for( int j = first; j < i; j++ )
            sum1 += *histp++;
        T sum2 = 0;
        for( int j = i; j <= last; j++ )
            sum2 += *histp++;
        new_cb->total = sum1;
        ptr->total = sum2;
    }
    new_cb->rmin = ptr->rmin;
    new_cb->rmax = ptr->rmax;
    new_cb->gmin = ptr->gmin;
    new_cb->gmax = ptr->gmax;
    new_cb->bmin = ptr->bmin;
    new_cb->bmax = ptr->bmax;
    switch( axis )
    {
      case RED:
        new_cb->rmax = i - 1;
        ptr->rmin = i;
        break;
      case GREEN:
        new_cb->gmax = i - 1;
        ptr->gmin = i;
        break;
      case BLUE:
        new_cb->bmax = i - 1;
        ptr->bmin = i;
        break;
    }

    if( nPixels != 0 &&
        static_cast<T>(new_cb->rmax - new_cb->rmin + 1) *
        static_cast<T>(new_cb->gmax - new_cb->gmin + 1) *
        static_cast<T>(new_cb->bmax - new_cb->bmin + 1) > nPixels )
    {
        shrinkboxFromBand(new_cb, pabyRedBand, pabyGreenBand, pabyBlueBand,
                          nPixels);
    }
    else if( psHashHistogram != NULL )
    {
        shrinkboxFromHashHistogram(new_cb, psHashHistogram);
    }
    else
    {
        shrinkbox(new_cb, histogram, nCLevels);
    }

    if( nPixels != 0 &&
        static_cast<T>(ptr->rmax - ptr->rmin + 1) *
        static_cast<T>(ptr->gmax - ptr->gmin + 1) *
        static_cast<T>(ptr->bmax - ptr->bmin + 1) > nPixels )
    {
        shrinkboxFromBand(ptr, pabyRedBand, pabyGreenBand, pabyBlueBand,
                          nPixels);
    }
    else if( psHashHistogram != NULL )
    {
        shrinkboxFromHashHistogram(ptr, psHashHistogram);
    }
    else
    {
        shrinkbox(ptr, histogram, nCLevels);
    }
}
Esempio n. 5
0
template<class T> int
GDALComputeMedianCutPCTInternal(
    GDALRasterBandH hRed,
    GDALRasterBandH hGreen,
    GDALRasterBandH hBlue,
    GByte* pabyRedBand,
    GByte* pabyGreenBand,
    GByte* pabyBlueBand,
    int (*pfnIncludePixel)(int, int, void*),
    int nColors,
    int nBits,
    T* panHistogram,  // NULL, or >= size (1<<nBits)^3 * sizeof(T) bytes.
    GDALColorTableH hColorTable,
    GDALProgressFunc pfnProgress,
    void * pProgressArg )

{
    VALIDATE_POINTER1( hRed, "GDALComputeMedianCutPCT", CE_Failure );
    VALIDATE_POINTER1( hGreen, "GDALComputeMedianCutPCT", CE_Failure );
    VALIDATE_POINTER1( hBlue, "GDALComputeMedianCutPCT", CE_Failure );

    CPLErr err = CE_None;

/* -------------------------------------------------------------------- */
/*      Validate parameters.                                            */
/* -------------------------------------------------------------------- */
    const int nXSize = GDALGetRasterBandXSize( hRed );
    const int nYSize = GDALGetRasterBandYSize( hRed );

    if( GDALGetRasterBandXSize( hGreen ) != nXSize
        || GDALGetRasterBandYSize( hGreen ) != nYSize
        || GDALGetRasterBandXSize( hBlue ) != nXSize
        || GDALGetRasterBandYSize( hBlue ) != nYSize )
    {
        CPLError(CE_Failure, CPLE_IllegalArg,
                 "Green or blue band doesn't match size of red band.");

        return CE_Failure;
    }

    if( pfnIncludePixel != NULL )
    {
        CPLError(CE_Failure, CPLE_IllegalArg,
                 "GDALComputeMedianCutPCT() doesn't currently support "
                 "pfnIncludePixel function.");

        return CE_Failure;
    }

    if( nColors <= 0 )
    {
        CPLError(CE_Failure, CPLE_IllegalArg,
                 "GDALComputeMedianCutPCT(): "
                 "nColors must be strictly greater than 1.");

        return CE_Failure;
    }

    if( nColors > 256 )
    {
        CPLError(CE_Failure, CPLE_IllegalArg,
                 "GDALComputeMedianCutPCT(): "
                 "nColors must be lesser than or equal to 256.");

        return CE_Failure;
    }

    if( pfnProgress == NULL )
        pfnProgress = GDALDummyProgress;

/* ==================================================================== */
/*      STEP 1: create empty boxes.                                     */
/* ==================================================================== */
    if( static_cast<GUInt32>(nXSize) >
        std::numeric_limits<T>::max() / static_cast<GUInt32>(nYSize) )
    {
        CPLError(CE_Warning, CPLE_AppDefined,
                 "GDALComputeMedianCutPCTInternal() not called "
                 "with large enough type");
    }

    T nPixels = 0;
    if( nBits == 8 && pabyRedBand != NULL && pabyGreenBand != NULL &&
        pabyBlueBand != NULL &&
        static_cast<GUInt32>(nXSize) <=
        std::numeric_limits<T>::max() / static_cast<GUInt32>(nYSize) )
    {
      nPixels = static_cast<T>(nXSize) * static_cast<T>(nYSize);
    }

    const int nCLevels = 1 << nBits;
    T* histogram = NULL;
    HashHistogram* psHashHistogram = NULL;
    if( panHistogram )
    {
        if( nBits == 8 && static_cast<GUIntBig>(nXSize) * nYSize <= 65536 )
        {
            // If the image is small enough, then the number of colors
            // will be limited and using a hashmap, rather than a full table
            // will be more efficient.
            histogram = NULL;
            psHashHistogram = (HashHistogram*)panHistogram;
            memset(psHashHistogram,
                   0xFF,
                   sizeof(HashHistogram) * PRIME_FOR_65536);
        }
        else
        {
            histogram = panHistogram;
            memset(histogram, 0, nCLevels*nCLevels*nCLevels * sizeof(T));
        }
    }
    else
    {
        histogram = static_cast<T*>(
            VSI_CALLOC_VERBOSE(nCLevels * nCLevels * nCLevels, sizeof(T)));
        if( histogram == NULL )
        {
            return CE_Failure;
        }
    }
    Colorbox *box_list =
        static_cast<Colorbox *>(CPLMalloc(nColors*sizeof (Colorbox)));
    Colorbox *freeboxes = box_list;
    freeboxes[0].next = &freeboxes[1];
    freeboxes[0].prev = NULL;
    for( int i = 1; i < nColors-1; ++i )
    {
        freeboxes[i].next = &freeboxes[i+1];
        freeboxes[i].prev = &freeboxes[i-1];
    }
    freeboxes[nColors-1].next = NULL;
    freeboxes[nColors-1].prev = &freeboxes[nColors-2];

/* ==================================================================== */
/*      Build histogram.                                                */
/* ==================================================================== */

/* -------------------------------------------------------------------- */
/*      Initialize the box datastructures.                              */
/* -------------------------------------------------------------------- */
    Colorbox *ptr = freeboxes;
    freeboxes = ptr->next;
    if( freeboxes )
        freeboxes->prev = NULL;
    Colorbox *usedboxes = NULL;  // TODO(schwehr): What?
    ptr->next = usedboxes;
    usedboxes = ptr;
    if( ptr->next )
        ptr->next->prev = ptr;

    ptr->rmin = 999;
    ptr->gmin = 999;
    ptr->bmin = 999;
    ptr->rmax = -1;
    ptr->gmax = -1;
    ptr->bmax = -1;
    ptr->total = static_cast<GUIntBig>(nXSize) * static_cast<GUIntBig>(nYSize);

/* -------------------------------------------------------------------- */
/*      Collect histogram.                                              */
/* -------------------------------------------------------------------- */

    // TODO(schwehr): Move these closer to usage after removing gotos.
    const int nColorShift = 8 - nBits;
    int nColorCounter = 0;
    GByte anRed[256] = {};
    GByte anGreen[256] = {};
    GByte anBlue[256] = {};

    GByte *pabyRedLine = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize));
    GByte *pabyGreenLine = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize));
    GByte *pabyBlueLine = static_cast<GByte *>(VSI_MALLOC_VERBOSE(nXSize));

    if( pabyRedLine == NULL ||
        pabyGreenLine == NULL ||
        pabyBlueLine == NULL )
    {
        err = CE_Failure;
        goto end_and_cleanup;
    }

    for( int iLine = 0; iLine < nYSize; iLine++ )
    {
        if( !pfnProgress( iLine / static_cast<double>(nYSize),
                          "Generating Histogram", pProgressArg ) )
        {
            CPLError( CE_Failure, CPLE_UserInterrupt, "User Terminated" );
            err = CE_Failure;
            goto end_and_cleanup;
        }

        err = GDALRasterIO( hRed, GF_Read, 0, iLine, nXSize, 1,
                      pabyRedLine, nXSize, 1, GDT_Byte, 0, 0 );
        if( err == CE_None )
            err = GDALRasterIO( hGreen, GF_Read, 0, iLine, nXSize, 1,
                      pabyGreenLine, nXSize, 1, GDT_Byte, 0, 0 );
        if( err == CE_None )
            err = GDALRasterIO( hBlue, GF_Read, 0, iLine, nXSize, 1,
                      pabyBlueLine, nXSize, 1, GDT_Byte, 0, 0 );
        if( err != CE_None )
            goto end_and_cleanup;

        for( int iPixel = 0; iPixel < nXSize; iPixel++ )
        {
            const int nRed = pabyRedLine[iPixel] >> nColorShift;
            const int nGreen = pabyGreenLine[iPixel] >> nColorShift;
            const int nBlue = pabyBlueLine[iPixel] >> nColorShift;

            ptr->rmin = std::min(ptr->rmin, nRed);
            ptr->gmin = std::min(ptr->gmin, nGreen);
            ptr->bmin = std::min(ptr->bmin, nBlue);
            ptr->rmax = std::max(ptr->rmax, nRed);
            ptr->gmax = std::max(ptr->gmax, nGreen);
            ptr->bmax = std::max(ptr->bmax, nBlue);

            bool bFirstOccurrence;
            if( psHashHistogram )
            {
                int* pnColor = FindAndInsertColorCount(psHashHistogram,
                                         MAKE_COLOR_CODE(nRed, nGreen, nBlue));
                bFirstOccurrence = ( *pnColor == 0 );
                (*pnColor)++;
            }
            else
            {
                T* pnColor =
                    HISTOGRAM(histogram, nCLevels, nRed, nGreen, nBlue);
                bFirstOccurrence = ( *pnColor == 0 );
                (*pnColor)++;
            }
            if( bFirstOccurrence)
            {
                if( nColorShift == 0 && nColorCounter < nColors )
                {
                    anRed[nColorCounter] = static_cast<GByte>(nRed);
                    anGreen[nColorCounter] = static_cast<GByte>(nGreen);
                    anBlue[nColorCounter] = static_cast<GByte>(nBlue);
                }
                nColorCounter++;
            }
        }
    }

    if( !pfnProgress( 1.0, "Generating Histogram", pProgressArg ) )
    {
        CPLError( CE_Failure, CPLE_UserInterrupt, "User Terminated" );
        err = CE_Failure;
        goto end_and_cleanup;
    }

    if( nColorShift == 0 && nColorCounter <= nColors )
    {
#if DEBUG_VERBOSE
        CPLDebug("MEDIAN_CUT", "%d colors found <= %d", nColorCounter, nColors);
#endif
        for( int iColor = 0; iColor < nColorCounter; iColor++ )
        {
            const GDALColorEntry sEntry =
            {
                static_cast<GByte>(anRed[iColor]),
                static_cast<GByte>(anGreen[iColor]),
                static_cast<GByte>(anBlue[iColor]),
                255
            };
            GDALSetColorEntry( hColorTable, iColor, &sEntry );
        }
        goto end_and_cleanup;
    }

/* ==================================================================== */
/*      STEP 3: continually subdivide boxes until no more free          */
/*      boxes remain or until all colors assigned.                      */
/* ==================================================================== */
    while( freeboxes != NULL )
    {
        ptr = largest_box(usedboxes);
        if( ptr != NULL )
            splitbox(ptr, histogram, psHashHistogram, nCLevels,
                     &freeboxes, &usedboxes,
                     pabyRedBand, pabyGreenBand, pabyBlueBand, nPixels);
        else
            freeboxes = NULL;
    }

/* ==================================================================== */
/*      STEP 4: assign colors to all boxes                              */
/* ==================================================================== */
    ptr = usedboxes;
    for( int i = 0; ptr != NULL; ++i, ptr = ptr->next )
    {
        const GDALColorEntry sEntry = {
            static_cast<GByte>(((ptr->rmin + ptr->rmax) << nColorShift) / 2),
            static_cast<GByte>(((ptr->gmin + ptr->gmax) << nColorShift) / 2),
            static_cast<GByte>(((ptr->bmin + ptr->bmax) << nColorShift) / 2),
            255
        };
        GDALSetColorEntry( hColorTable, i, &sEntry );
    }

end_and_cleanup:
    CPLFree( pabyRedLine );
    CPLFree( pabyGreenLine );
    CPLFree( pabyBlueLine );

    // We're done with the boxes now.
    CPLFree(box_list);
    freeboxes = NULL;
    usedboxes = NULL;

    if( panHistogram == NULL )
        CPLFree( histogram );

    return err;
}
Esempio n. 6
0
template<class T> static void
shrinkbox( Colorbox* box, const T* histogram, int nCLevels )
{
    if( box->rmax > box->rmin )
    {
        for( int ir = box->rmin; ir <= box->rmax; ++ir )
        {
            for( int ig = box->gmin; ig <= box->gmax; ++ig )
            {
                const T *histp =
                    HISTOGRAM(histogram, nCLevels, ir, ig, box->bmin);
                for( int ib = box->bmin; ib <= box->bmax; ++ib )
                {
                    if( *histp++ != 0 )
                    {
                        box->rmin = ir;
                        goto have_rmin;
                    }
                }
            }
        }
    }
    have_rmin:
    if( box->rmax > box->rmin )
    {
        for( int ir = box->rmax; ir >= box->rmin; --ir )
        {
            for( int ig = box->gmin; ig <= box->gmax; ++ig )
            {
                const T *histp =
                    HISTOGRAM(histogram, nCLevels, ir, ig, box->bmin);
                for( int ib = box->bmin; ib <= box->bmax; ++ib )
                {
                    if( *histp++ != 0 )
                    {
                        box->rmax = ir;
                        goto have_rmax;
                    }
                }
            }
        }
    }

    have_rmax:
    if( box->gmax > box->gmin )
    {
        for( int ig = box->gmin; ig <= box->gmax; ++ig )
        {
            for( int ir = box->rmin; ir <= box->rmax; ++ir )
            {
                const T *histp =
                    HISTOGRAM(histogram, nCLevels, ir, ig, box->bmin);
                for( int ib = box->bmin; ib <= box->bmax; ++ib )
                {
                    if( *histp++ != 0 )
                    {
                        box->gmin = ig;
                        goto have_gmin;
                    }
                }
            }
        }
    }

    have_gmin:
    if( box->gmax > box->gmin )
    {
        for( int ig = box->gmax; ig >= box->gmin; --ig )
        {
            for( int ir = box->rmin; ir <= box->rmax; ++ir )
            {
                const T *histp =
                    HISTOGRAM(histogram, nCLevels, ir, ig, box->bmin);
                for( int ib = box->bmin; ib <= box->bmax; ++ib )
                {
                    if( *histp++ != 0 )
                    {
                        box->gmax = ig;
                        goto have_gmax;
                    }
                }
            }
        }
    }

    have_gmax:
    if( box->bmax > box->bmin )
    {
        for( int ib = box->bmin; ib <= box->bmax; ++ib )
        {
            for( int ir = box->rmin; ir <= box->rmax; ++ir )
            {
                const T *histp =
                    HISTOGRAM(histogram, nCLevels, ir, box->gmin, ib);
                for( int ig = box->gmin; ig <= box->gmax; ++ig )
                {
                    if( *histp != 0 )
                    {
                        box->bmin = ib;
                        goto have_bmin;
                    }
                    histp += nCLevels;
                }
            }
        }
    }

    have_bmin:
    if( box->bmax > box->bmin )
    {
        for( int ib = box->bmax; ib >= box->bmin; --ib )
        {
            for( int ir = box->rmin; ir <= box->rmax; ++ir )
            {
                const T *histp =
                    HISTOGRAM(histogram, nCLevels, ir, box->gmin, ib);
                for( int ig = box->gmin; ig <= box->gmax; ++ig )
                {
                    if( *histp != 0 )
                    {
                        box->bmax = ib;
                        goto have_bmax;
                    }
                    histp += nCLevels;
                }
            }
        }
    }

    have_bmax:
    ;
}