Initial import
git-svn-id: http://moon:8086/svn/software/trunk/libsrc/_to_be_added@1 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
@@ -0,0 +1,418 @@
|
||||
// ------------------------------------------------------------
|
||||
// clob.c
|
||||
//
|
||||
// A color quantizer using binary-split technique
|
||||
// From:
|
||||
// "Color Quantization of Images", Orchard, Bouman
|
||||
// IEEE Trans. on Sig. Proc., vol. 39, no. 12, pp. 2677-2690, Dec. 1991.
|
||||
//
|
||||
// 10.03.2005, J.Ahrensfeld
|
||||
// ------------------------------------------------------------
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <sys/time.h>
|
||||
#include "bintree.h"
|
||||
#include "mutil.h"
|
||||
#include "lapack_cwrap.h"
|
||||
#include "clob.h"
|
||||
|
||||
// ------------------------------------------------------------
|
||||
void CodebookAlloc(codebook_t *pObj, int N_max, int M_max)
|
||||
{
|
||||
int i;
|
||||
|
||||
pObj->pColor = (color_vector_t*)malloc(M_max*sizeof(color_vector_t));
|
||||
pObj->size_C = (int*)malloc(M_max*sizeof(int));
|
||||
memset(pObj->size_C, 0, M_max*sizeof(int));
|
||||
pObj->pC = (int*)malloc(N_max*sizeof(int));
|
||||
pObj->ppC = (int**)malloc(M_max*sizeof(int*));
|
||||
|
||||
pObj->ppC[0] = pObj->pC;;
|
||||
for (i=1; i < M_max; i++)
|
||||
pObj->ppC[i] = NULL;
|
||||
|
||||
pObj->max_colors = M_max;
|
||||
pObj->max_samples = N_max;
|
||||
pObj->num_colors = 0;
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
void CodebookFree(codebook_t *pObj)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(!pObj)
|
||||
return;
|
||||
|
||||
free(pObj->pC);
|
||||
free(pObj->ppC);
|
||||
free(pObj->pColor);
|
||||
free(pObj->size_C);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
void ColorQuant_Init(colorquant_t *pCQ, int N_max, int M_max)
|
||||
{
|
||||
M_max++;
|
||||
pCQ->N_max = N_max;
|
||||
pCQ->M_max = M_max;
|
||||
|
||||
pCQ->pRootData = (node_data_t*)malloc(sizeof(node_data_t));
|
||||
memset(pCQ->pRootData, 0, sizeof(node_data_t));
|
||||
|
||||
pCQ->pData = (node_data_t*)malloc(2*M_max*sizeof(node_data_t));
|
||||
memset(pCQ->pData, 0, 2*M_max*sizeof(node_data_t));
|
||||
|
||||
pCQ->pTemp = (double*)malloc(N_max*sizeof(double));
|
||||
pCQ->pXs = (color_vector_t*)malloc(N_max*sizeof(color_vector_t));
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
void ColorQuant_Free(colorquant_t *pCQ)
|
||||
{
|
||||
int m;
|
||||
|
||||
FreeNodeData(pCQ->pRootData);
|
||||
for (m=0; m < 2*pCQ->M_max; m++)
|
||||
{
|
||||
FreeNodeData(&pCQ->pData[m]);
|
||||
}
|
||||
free(pCQ->pRootData);
|
||||
pCQ->pRootData = NULL;
|
||||
free(pCQ->pData);
|
||||
pCQ->pData = NULL;
|
||||
free(pCQ->pXs);
|
||||
free(pCQ->pTemp);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
void FreeNodeData(node_data_t *pObj)
|
||||
{
|
||||
if(pObj)
|
||||
{
|
||||
if(pObj->pC)
|
||||
{
|
||||
free(pObj->pC);
|
||||
pObj->pC = NULL;
|
||||
}
|
||||
if(pObj->pExpr_left)
|
||||
{
|
||||
free(pObj->pExpr_left);
|
||||
pObj->pExpr_left = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
void ColorNodeStat(colorquant_t *pCQ, node_data_t *pObj, color_vector_t *pXs)
|
||||
{
|
||||
int i, j, s, info;
|
||||
|
||||
if (pObj->N == 0)
|
||||
{
|
||||
fprintf(stderr, "ColorNodeStat(): N is zero!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Calc node statistics
|
||||
// R = sum_s(xs_s*xs_s') ; mit s = Element aus Menge C
|
||||
memset(pObj->R, 0, ROW_DIM*ROW_DIM*sizeof(double));
|
||||
dsyrk('U', 'N', ROW_DIM, pObj->N, 1.0, (double*)pXs, ROW_DIM, 1.0, (double*)pObj->R, ROW_DIM);
|
||||
// PrintMatrix("R=",(double*)pObj->R, ROW_DIM, ROW_DIM);
|
||||
|
||||
// m = sum_s(xs_s)
|
||||
memset(pObj->m, 0, ROW_DIM*sizeof(double));
|
||||
for(i=0; i < pObj->N; i++)
|
||||
{
|
||||
pObj->m[0] += pXs[i][0];
|
||||
pObj->m[1] += pXs[i][1];
|
||||
pObj->m[2] += pXs[i][2];
|
||||
|
||||
}
|
||||
// PrintMatrix("m=",(double*)pObj->m, ROW_DIM, 1);
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
double ColorLambda(colorquant_t *pCQ, node_data_t *pObj, color_vector_t *pXs)
|
||||
{
|
||||
|
||||
int i, s, info, lwork;
|
||||
color_vector_t d = {0};
|
||||
double *pWork;
|
||||
double *pDiff, Ls;
|
||||
|
||||
if (pObj->N == 0)
|
||||
{
|
||||
fprintf(stderr, "ColorLambda(): N is zero!\n");
|
||||
pObj->lambda = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
pObj->pExpr_left = (double*)malloc(pObj->N*sizeof(double));
|
||||
|
||||
// q = m/N;
|
||||
memcpy(pObj->q, pObj->m, sizeof(color_vector_t));
|
||||
dscal (ROW_DIM, 1.0/pObj->N, pObj->q, 1);
|
||||
// PrintMatrix("q=",(double*)pObj->q, ROW_DIM, 1);
|
||||
|
||||
// cov = R - 1/N*m*m'
|
||||
memcpy(pObj->cov, pObj->R, ROW_DIM*sizeof(color_vector_t));
|
||||
dsyr('U', ROW_DIM, -1.0/pObj->N, pObj->m, 1, (double*)pObj->cov, ROW_DIM);
|
||||
// PrintMatrix("Cov=",(double*)pObj->cov, ROW_DIM, ROW_DIM);
|
||||
|
||||
// Query dsyev() for optimal work buffer size
|
||||
pWork = pCQ->pTemp;
|
||||
pWork[0] = 0;
|
||||
info = dsyev('V', 'U', ROW_DIM, (double*)NULL, ROW_DIM, NULL, pWork, -1);
|
||||
lwork = (int)pWork[0];
|
||||
|
||||
// d = eig(cov)
|
||||
info = dsyev('V', 'U', ROW_DIM, (double*)pObj->cov, ROW_DIM, d, pWork, lwork);
|
||||
if (info != 0)
|
||||
{
|
||||
fprintf (stderr, "Eigenvalue solver failure with error %d\n", info);
|
||||
printf("N=%d\n", pObj->N);
|
||||
PrintMatrix("Cov=",(double*)pObj->cov, ROW_DIM, ROW_DIM);
|
||||
}
|
||||
|
||||
// PrintMatrix("d=",(double*)d, ROW_DIM, 1);
|
||||
// PrintMatrix("V=",(double*)pObj->cov, ROW_DIM, ROW_DIM);
|
||||
|
||||
// Form unit-vector e in direction of max. element in d
|
||||
dcopy (ROW_DIM, d, 1, pObj->e, 1);
|
||||
GetPrincipleEigenVector((double*)pObj->cov, (double*)pObj->e, ROW_DIM);
|
||||
// PrintMatrix("e=",(double*)pObj->e, ROW_DIM, 1);
|
||||
|
||||
// -------------------------
|
||||
// Compute Lambda
|
||||
|
||||
// Expr. left: dot(xs,e) = e'*xs_s = xs_s'*e
|
||||
// Also used later in ColorSplit()
|
||||
dgemv('T', ROW_DIM, pObj->N, 1.0, (double*)pXs, ROW_DIM, pObj->e, 1, 0.0, pObj->pExpr_left, 1);
|
||||
|
||||
// Expr. right: dot(q,e) = e'*q = q'*e
|
||||
// Also used later in ColorSplit()
|
||||
pObj->expr_right = ddot(ROW_DIM, pObj->q, 1, pObj->e, 1);
|
||||
|
||||
// lambda = sum_s((xs_s - q)'*e).^2);
|
||||
pObj->lambda = 0;
|
||||
for (i=0; i < pObj->N; i++)
|
||||
{
|
||||
// xs_s'*e - q'*e
|
||||
Ls = pObj->pExpr_left[i] - pObj->expr_right;
|
||||
pObj->lambda += Ls*Ls;
|
||||
}
|
||||
return pObj->lambda;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
void ColorNodeSplit(colorquant_t *pCQ, node_data_t *pObj, node_data_t *pData2n, node_data_t *pData2n1)
|
||||
{
|
||||
int N2n, N2n1, s, i;
|
||||
|
||||
memset(pData2n, 0, sizeof(node_data_t));
|
||||
memset(pData2n1, 0, sizeof(node_data_t));
|
||||
|
||||
pData2n->pC = (int*)malloc(pObj->N*sizeof(int));
|
||||
if(!pData2n->pC)
|
||||
{
|
||||
fprintf(stderr, "pData2n->pC = NULL for N=%d\n", pObj->N);
|
||||
}
|
||||
|
||||
pData2n1->pC = (int*)malloc(pObj->N*sizeof(int));
|
||||
if(!pData2n1->pC)
|
||||
{
|
||||
fprintf(stderr, "pData2n1->pC = NULL for N=%d\n", pObj->N);
|
||||
}
|
||||
|
||||
// Split into two new sets
|
||||
N2n = 0;
|
||||
N2n1 = 0;
|
||||
for (i=0; i < pObj->N; i++)
|
||||
{
|
||||
s = pObj->pC[i];
|
||||
|
||||
if(pObj->pExpr_left[i] > pObj->expr_right)
|
||||
{
|
||||
pData2n1->pC[N2n1] = s;
|
||||
N2n1++;
|
||||
}
|
||||
else
|
||||
{
|
||||
pData2n->pC[N2n] = s;
|
||||
N2n++;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute statistics of two new nodes
|
||||
// Node(2n)
|
||||
pData2n->N = N2n;
|
||||
for (i=0; i < N2n; i++)
|
||||
{
|
||||
s = pData2n->pC[i];
|
||||
pCQ->pXs[i][0] = pCQ->pX[s][0];
|
||||
pCQ->pXs[i][1] = pCQ->pX[s][1];
|
||||
pCQ->pXs[i][2] = pCQ->pX[s][2];
|
||||
}
|
||||
|
||||
ColorNodeStat(pCQ, pData2n, pCQ->pXs);
|
||||
ColorLambda(pCQ, pData2n, pCQ->pXs);
|
||||
|
||||
// Node(2n+1)
|
||||
pData2n1->N = N2n1;
|
||||
for(i=0; i < ROW_DIM; i++)
|
||||
{
|
||||
pData2n1->R[i][0] = pObj->R[i][0] - pData2n->R[i][0];
|
||||
pData2n1->R[i][1] = pObj->R[i][1] - pData2n->R[i][1];
|
||||
pData2n1->R[i][2] = pObj->R[i][2] - pData2n->R[i][2];
|
||||
}
|
||||
|
||||
for(i=0; i < ROW_DIM; i++)
|
||||
pData2n1->m[i] = pObj->m[i] - pData2n->m[i];
|
||||
|
||||
for (i=0; i < N2n1; i++)
|
||||
{
|
||||
s = pData2n1->pC[i];
|
||||
pCQ->pXs[i][0] = pCQ->pX[s][0];
|
||||
pCQ->pXs[i][1] = pCQ->pX[s][1];
|
||||
pCQ->pXs[i][2] = pCQ->pX[s][2];
|
||||
}
|
||||
ColorLambda(pCQ, pData2n1, pCQ->pXs);
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
int ColorQuant(colorquant_t *pCQ, codebook_t *pCB, color_vector_t *pX, int K, int N, int M, double lambda_min)
|
||||
{
|
||||
int i, m, *pC, bst_state, s, sum_pixel, codebook_size, size, *ptr, *ptr_next;
|
||||
node_data_t *pData, *pData2n, *pData2n1;
|
||||
node_t *node_max, *node_temp;
|
||||
bintree_t bst;
|
||||
|
||||
if (N == 0)
|
||||
{
|
||||
fprintf(stderr, "ColorQuant(): N is zero!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pCQ->nRow = K;
|
||||
pCQ->nCol = N;
|
||||
|
||||
pCQ->pRootData->N = N;
|
||||
pCQ->pX = (color_vector_t*)pX;
|
||||
|
||||
pCQ->pRootData->pC = (int*)malloc(N*sizeof(int));
|
||||
|
||||
// Create root data set
|
||||
for(i=0; i < N; i++)
|
||||
{
|
||||
pCQ->pRootData->pC[i] = i; // store indices of vector boundaries
|
||||
}
|
||||
|
||||
ColorNodeStat(pCQ, pCQ->pRootData, pCQ->pX);
|
||||
ColorLambda(pCQ, pCQ->pRootData, pCQ->pX);
|
||||
|
||||
// Create root-node
|
||||
bintree_init(&bst, 2*N);
|
||||
|
||||
bintree_insert(&bst, pCQ->pRootData->lambda, pCQ->pRootData);
|
||||
|
||||
for (m=0; m < M-1; m++)
|
||||
{
|
||||
node_max = bintree_GetNodeMax(&bst);
|
||||
if (!node_max)
|
||||
{
|
||||
fprintf(stderr,"node_max = NULL!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (node_max->value < lambda_min)
|
||||
break;
|
||||
|
||||
pData2n = &pCQ->pData[2*m];
|
||||
pData2n1 = &pCQ->pData[2*m+1];
|
||||
ColorNodeSplit(pCQ, (node_data_t*)node_max->pData, pData2n, pData2n1);
|
||||
if (pData2n->N > 0)
|
||||
{
|
||||
bintree_insert(&bst, pData2n->lambda, pData2n);
|
||||
}
|
||||
else
|
||||
{
|
||||
FreeNodeData(pData2n);
|
||||
}
|
||||
|
||||
if (pData2n1->lambda > 0)
|
||||
{
|
||||
bintree_insert(&bst, pData2n1->lambda, pData2n1);
|
||||
}
|
||||
else
|
||||
{
|
||||
FreeNodeData(pData2n1);
|
||||
}
|
||||
|
||||
// if ((pData2n->lambda == 0) || (pData2n1->lambda == 0))
|
||||
// {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
node_temp = bintree_node_remove(&bst, node_max);
|
||||
if (node_temp == bst.pRoot)
|
||||
{
|
||||
break;
|
||||
}
|
||||
FreeNodeData((node_data_t*)node_max->pData);
|
||||
|
||||
if (!bst.pRoot)
|
||||
break;
|
||||
|
||||
bst_state = bintree_isBST(bst.pRoot);
|
||||
if (!bst_state)
|
||||
{
|
||||
fprintf(stderr,"Binary Tree is not BST!\n");
|
||||
}
|
||||
}
|
||||
|
||||
// bintree_print(pCQ->root);
|
||||
// printf("\n");
|
||||
sum_pixel = 0;
|
||||
codebook_size = 0;
|
||||
pCB->ppC[0] = pCB->pC;
|
||||
do
|
||||
{
|
||||
node_max = bintree_GetNodeMax(&bst);
|
||||
if (!node_max)
|
||||
{
|
||||
fprintf(stderr,"node_max = NULL!\n");
|
||||
}
|
||||
// printf("Lambda=%5.5g\n",node_max->value);
|
||||
|
||||
size = ((node_data_t*)node_max->pData)->N;
|
||||
pCB->size_C[codebook_size] = size;
|
||||
ptr = pCB->ppC[codebook_size];
|
||||
ptr_next = ptr + size;
|
||||
sum_pixel += size;
|
||||
memcpy(ptr,((node_data_t*)node_max->pData)->pC, size*sizeof(int));
|
||||
memcpy(pCB->pColor[codebook_size],((node_data_t*)(node_max->pData))->q, sizeof(color_vector_t));
|
||||
if ((codebook_size+1) < pCB->max_colors)
|
||||
pCB->ppC[codebook_size+1] = (int*)(ptr_next);
|
||||
|
||||
FreeNodeData((node_data_t*)(node_max->pData));
|
||||
node_temp = bintree_node_remove(&bst, node_max);
|
||||
codebook_size++;
|
||||
|
||||
} while(node_temp);
|
||||
pCB->num_colors = codebook_size;
|
||||
|
||||
// printf("Num. pixels = %d\n",sum_pixel);
|
||||
// printf("Codebook size = %d\n",codebook_size);
|
||||
// PrintMatrix("Codebook=",(double*)pCB->pColor, ROW_DIM, codebook_size);
|
||||
|
||||
FreeNodeData(pCQ->pRootData);
|
||||
bintree_free(&bst);
|
||||
return codebook_size;
|
||||
}
|
||||
Reference in New Issue
Block a user