static void qualityToMinColorError(TColorErrorParameter* out_errorParameter,float& colorQuality,bool isMustFitColorTable){ if (colorQuality>100) colorQuality=100; else if (colorQuality<0) colorQuality=0; const TInt32 kDiffuseCoeff0=(1<<kColorErrorDiffuseCoefficientIntFloatBit)*87/100; const TInt32 kDiffuseCoeff100=(1<<kColorErrorDiffuseCoefficientIntFloatBit)*97/100; out_errorParameter->errorDiffuse_coefficient=(TInt32)(0.5f+kDiffuseCoeff0+(kDiffuseCoeff100-kDiffuseCoeff0)*colorQuality/100); const TInt32 kMaxDiffuseValue0=(1<<kColorErrorDiffuseCoefficientIntFloatBit)*(1<<5); const TInt32 kMaxDiffuseValue100=(1<<kColorErrorDiffuseCoefficientIntFloatBit)*(1<<2); out_errorParameter->maxErrorDiffuseValue=(TInt32)(0.5f+kMaxDiffuseValue0+(kMaxDiffuseValue100-kMaxDiffuseValue0)*colorQuality/100); out_errorParameter->isMustFitColorTable=isMustFitColorTable;//colorQuality<=80; static TInt32 kSingleColorError0=getColorDistance(Color24(150,150,150),Color24(0,0,0)); static TInt32 kSingleColorError60=getColorDistance(Color24((1<<5)-1,(1<<5)-1,(1<<6)-1),Color24(0,0,0)); static TInt32 kSingleColorError80=getColorDistance(Color24((1<<3)-1,(1<<3)-1,(1<<3)-1),Color24(0,0,0)); static TInt32 kSingleColorError100=0; static TInt32 kTableSize0=2; static TInt32 kTableSize60=12; static TInt32 kTableSize80=16; if ((80<=colorQuality)&&(colorQuality<=100)){ out_errorParameter->minColorError=(TInt32)(0.5f+(colorQuality-80)*(kSingleColorError100-kSingleColorError80)/(100-80)+kSingleColorError80); out_errorParameter->minColorError_optimize=(out_errorParameter->minColorError)>>1; out_errorParameter->maxTableSize=16; return; }else if ((60<=colorQuality)&&(colorQuality<80)){
//-------------------------------------------------------------- void testApp::draw(){ ofLog(OF_LOG_NOTICE, "draw"+ofToString(ofGetFrameNum())); if (!saveToFile) { if (counter <= image1.getWidth()*image1.getHeight()) { // 左の画像を右の画像に入れ替える ofPoint referencePoint; if (enableRandomExchange) { //ランダムで交換 referencePoint = ofPoint(exchangeOrderVector[counter]%(int)image1.getWidth(), exchangeOrderVector[counter]/(int)image1.getWidth()); }else{ //上から順に交換 referencePoint = ofPoint(counter%(int)image1.getWidth(), counter/(int)image1.getWidth()); } ofColor referenceColor = image1.getColor(referencePoint.x, referencePoint.y); double minimumDistance = image1.getWidth()+image2.getHeight(); ofPoint minimumDistancePoint; unsigned char * checkImagePixels = image2.getPixels(); // 最小の距離の色を調べる for (int i=0; i<image1.getHeight(); i++) { for (int j=0; j<image1.getWidth(); j++) { if (!enableDuplicate) { // 重複を許さない if (!usedOrNotVector[i*(int)image2.getWidth()+j]) { ofColor checkColor = ofColor(checkImagePixels[(i*(int)image2.getWidth()+j)*3], checkImagePixels[(i*(int)image2.getWidth()+j)*3+1], checkImagePixels[(i*(int)image2.getWidth()+j)*3+2]); double checkDistance = getColorDistance(referenceColor, checkColor); if (checkDistance < minimumDistance) { if (!usedOrNotVector[i*(int)image2.getWidth()+j]) { minimumDistance = checkDistance; minimumDistancePoint = ofPoint(j, i); } // 同じ色の重複を許す minimumDistance = checkDistance; minimumDistancePoint = ofPoint(j, i); } } } else{ ofColor checkColor = ofColor(checkImagePixels[(i*(int)image2.getWidth()+j)*3], checkImagePixels[(i*(int)image2.getWidth()+j)*3+1], checkImagePixels[(i*(int)image2.getWidth()+j)*3+2]); double checkDistance = getColorDistance(referenceColor, checkColor); if (checkDistance < minimumDistance) { if (!usedOrNotVector[i*(int)image2.getWidth()+j]) { minimumDistance = checkDistance; minimumDistancePoint = ofPoint(j, i); } // 同じ色の重複を許す minimumDistance = checkDistance; minimumDistancePoint = ofPoint(j, i); } } } } //最も近い距離の色の組み合わせをベクターに保存 pointPair tempPointPair; tempPointPair.point1 = referencePoint; tempPointPair.point2 = minimumDistancePoint; // 重複を許さない if (!enableDuplicate) { //再利用しないために、使用したPointを保存 usedOrNotVector[minimumDistancePoint.y*(int)image2.getWidth()+minimumDistancePoint.x] = true; } pointPairVector.push_back(tempPointPair); // ofLog(OF_LOG_NOTICE, "X:"+ofToString(pointPairVector.back().point2.x)+" Y:"+ofToString(pointPairVector.back().point2.y)); // 左の画像の色を入れ替える image1.setColor(pointPairVector.back().point1.x, pointPairVector.back().point1.y, image2.getColor(pointPairVector.back().point2.x, pointPairVector.back().point2.y)); image1.update(); // 右の画像の色を入れ替える if (enableExchange) { image2.setColor(pointPairVector.back().point2.x, pointPairVector.back().point2.y, originalImage1.getColor(pointPairVector.back().point1.x, pointPairVector.back().point1.y)); image2.update(); } } // draw image image1.draw(ofPoint(ofGetWidth()/4.-image1.getWidth()/2.+100, (ofGetHeight()-image1.getHeight())/2.), image1.getWidth(), image1.getHeight()); image2.draw(ofPoint(ofGetWidth()/4.*3-image2.getWidth()/2.-100 , (ofGetHeight()-image2.getHeight())/2.), image2.getWidth(), image2.getHeight()); //hightLihgting if (counter <= image1.getWidth()*image1.getHeight()) { ofPushStyle(); ofSetColor(ofColor::white); ofSetLineWidth(1); ofLine(pointPairVector.back().point1.x+(ofGetWidth()/4.-image1.getWidth()/2.+100), pointPairVector.back().point1.y+((ofGetHeight()-image1.getHeight())/2.), pointPairVector.back().point2.x+(ofGetWidth()/4.*3-image2.getWidth()/2.-100), pointPairVector.back().point2.y+((ofGetHeight()-image2.getHeight())/2.)); ofPopStyle(); } // ofPushStyle(); // ofSetColor(255, 255, 0, 127); // ofCircle(300, 100, 150); // ofSetColor(0, 255, 255, 127); // ofCircle(100, 100, 150); // // ofPopStyle(); } }
//-------------------------------------------------------------- void testApp::keyReleased(int key){ switch (key) { case 'f': ofToggleFullscreen(); break; case '0': ofEnableBlendMode(OF_BLENDMODE_DISABLED); break; case '1': ofEnableBlendMode(OF_BLENDMODE_ALPHA); break; case '2': ofEnableBlendMode(OF_BLENDMODE_ADD); break; case '3': ofEnableBlendMode(OF_BLENDMODE_SUBTRACT); break; case '4': ofEnableBlendMode(OF_BLENDMODE_MULTIPLY); break; case '5': ofEnableBlendMode(OF_BLENDMODE_SCREEN); break; case 'a': ofEnableAntiAliasing(); break; case 'b': ofBackground(0, 0, 0, 255); break; case 'd': ofDisableAlphaBlending(); break; case 'e': ofEnableAlphaBlending(); break; case 'r': //read file importFileForStruct(); break; case 's': ofDisableAntiAliasing(); break; case 'w': ofBackground(255, 255, 255, 255); break; case ' ': { saveToFile = true; ofLog(OF_LOG_NOTICE, "calculating..."); //ペアのデータを作成 --> vector<pointPair> pointPairVectorForWriting; for (int k=0; k<image1.getWidth()*image1.getHeight(); k++) { if (k <= image1.getWidth()*image1.getHeight()) { // 左の画像を右の画像に入れ替える ofPoint referencePoint; if (enableRandomExchange) { //ランダムで交換 referencePoint = ofPoint(exchangeOrderVector[k]%(int)image1.getWidth(), exchangeOrderVector[k]/(int)image1.getWidth()); }else{ //上から順に交換 referencePoint = ofPoint(k%(int)image1.getWidth(), k/(int)image1.getWidth()); } ofColor referenceColor = image1.getColor(referencePoint.x, referencePoint.y); double minimumDistance = image1.getWidth()+image2.getHeight(); ofPoint minimumDistancePoint; unsigned char * checkImagePixels = image2.getPixels(); // 最小の距離の色を調べる for (int i=0; i<image1.getHeight(); i++) { for (int j=0; j<image1.getWidth(); j++) { if (!enableDuplicate) { // 重複を許さない if (!usedOrNotVector[i*(int)image2.getWidth()+j]) { ofColor checkColor = ofColor(checkImagePixels[(i*(int)image2.getWidth()+j)*3], checkImagePixels[(i*(int)image2.getWidth()+j)*3+1], checkImagePixels[(i*(int)image2.getWidth()+j)*3+2]); double checkDistance = getColorDistance(referenceColor, checkColor); if (checkDistance < minimumDistance) { if (!usedOrNotVector[i*(int)image2.getWidth()+j]) { minimumDistance = checkDistance; minimumDistancePoint = ofPoint(j, i); } // 同じ色の重複を許す minimumDistance = checkDistance; minimumDistancePoint = ofPoint(j, i); } } } else{ ofColor checkColor = ofColor(checkImagePixels[(i*(int)image2.getWidth()+j)*3], checkImagePixels[(i*(int)image2.getWidth()+j)*3+1], checkImagePixels[(i*(int)image2.getWidth()+j)*3+2]); double checkDistance = getColorDistance(referenceColor, checkColor); if (checkDistance < minimumDistance) { if (!usedOrNotVector[i*(int)image2.getWidth()+j]) { minimumDistance = checkDistance; minimumDistancePoint = ofPoint(j, i); } // 同じ色の重複を許す minimumDistance = checkDistance; minimumDistancePoint = ofPoint(j, i); } } } } //最も近い距離の色の組み合わせをベクターに保存 pointPair tempPointPair; tempPointPair.point1 = referencePoint; tempPointPair.point2 = minimumDistancePoint; // 重複を許さない if (!enableDuplicate) { //再利用しないために、使用したPointを保存 usedOrNotVector[minimumDistancePoint.y*(int)image2.getWidth()+minimumDistancePoint.x] = true; } pointPairVectorForWriting.push_back(tempPointPair); } } ofLog(OF_LOG_NOTICE, "pointPairVectorForWriting done!"); //<-- ペアのデータを作成 ofLog(OF_LOG_NOTICE, "X1:"+ofToString(pointPairVectorForWriting[0].point1.x)+" Y1:"+ofToString(pointPairVectorForWriting[0].point1.y)); ofLog(OF_LOG_NOTICE, "X2:"+ofToString(pointPairVectorForWriting[0].point2.x)+" Y2:"+ofToString(pointPairVectorForWriting[0].point2.y)); exportFileForStruct(pointPairVectorForWriting); ofLog(OF_LOG_NOTICE, ofToString("writing file...")); saveToFile = false; ofLog(OF_LOG_NOTICE, "done"); } break; default: break; } }
void DKHFastScanning(LPIMGDATA imgData){ int i, j, clusterCount, maxSize; CLUSIMG clusImg; //ALLOCDATA delLists; float threshold, dist; Cluster *clusterList, *Ci, *lastClus; char strThreshold[16]; clusterCount = 1; threshold = 45.0f; clusImg.width = imgData->width; clusImg.height = imgData->height; clusImg.pixClus = (void**)HeapAlloc(GetProcessHeap(),0,clusImg.width*clusImg.height*sizeof(void*)); writeConsole("\nThreshold distance: "); readConsoleString(strThreshold); threshold = atof(strThreshold); if(threshold < 1.0f) threshold = 50.0f; writeConsoleFmt("We'll be using threshold %.2f\n",threshold); LPCOLOR thisPx = (LPCOLOR)imgData->bitmap; Ci = new Cluster(0,0,*thisPx,&clusImg); lastClus = clusterList = Ci; thisPx++; for(j = 1; j < clusImg.width; j++){ Ci = getPixelCluster(clusterList,&clusImg,j-1,0); dist = getColorDistance(Ci->getTone(),*thisPx); if(dist < threshold) Ci->mergePoint(j,0,*thisPx); else{ Ci = new Cluster(j,0,*thisPx,&clusImg); lastClus->setNext(Ci); Ci->setBefore(lastClus); lastClus = Ci; clusterCount++; } thisPx++; } for(i = 1; i < clusImg.height; i++){ Ci = getPixelCluster(clusterList,&clusImg,0,i-1); dist = getColorDistance(Ci->getTone(),*thisPx); if(dist < threshold) Ci->mergePoint(0,i,*thisPx); else{ Ci = new Cluster(0,i,*thisPx,&clusImg); lastClus->setNext(Ci); Ci->setBefore(lastClus); lastClus = Ci; clusterCount++; } thisPx++; for(j = 1; j < clusImg.width; j++){ Cluster* Cu = getPixelCluster(clusterList,&clusImg,j,i-1); Cluster* Cl = getPixelCluster(clusterList,&clusImg,j-1,i); dist = getColorDistance(Cu->getTone(),*thisPx); if(dist < threshold){ Cu->mergePoint(j,i,*thisPx); dist = getColorDistance(Cl->getTone(),*thisPx); if(dist < threshold){ if(Cu != Cl){ clusterCount--; if(Cl != clusterList){ if(Cl == lastClus) lastClus = lastClus->getBefore(); Cu->mergeCluster(Cl,clusterList); }else{ if(Cu == lastClus) lastClus = lastClus->getBefore(); Cl->mergeCluster(Cu,clusterList); } } } }else{ dist = getColorDistance(Cl->getTone(),*thisPx); if(dist < threshold) Cl->mergePoint(j,i,*thisPx); else{ Ci = new Cluster(j,i,*thisPx,&clusImg); lastClus->setNext(Ci); Ci->setBefore(lastClus); lastClus = Ci; clusterCount++; } } thisPx++; } writeConsoleFmt("Line %d done. Cluster count %d.\n",i,clusterCount); //dbgShow(clusterList,&clusImg); } j = 0; //Remove small clusters (less than 1%) writeConsoleFmt("Wich it's the minimum cluster size(size threshold in percent)?"); readConsoleString(strThreshold); threshold = atof(strThreshold)/100.0f; if(threshold > 0.1f){ writeConsole("Too big. You should had inserted values lower than 10.0\n"); threshold = 0.01f; }else if(threshold < 0.0001f){ writeConsole("Too small. You should had inserted values greater than 0.01\n"); threshold = 0.01f; } writeConsoleFmt("Minimal cluster size to image ratio: %.4f%%\n",threshold*100.0f); maxSize = (int)((clusImg.width*clusImg.height)*threshold); maxSize = (clusImg.width*clusImg.height)/400; //Get how much is 1% Ci = clusterList->getNext(); i = 0; while(Ci != (Cluster*)NULL){ if(Ci->getCount() < maxSize){ Cluster* delClus = Ci; j++; writeConsoleFmt("Merging cluster %08x because of low pixel count: %d. Clusters deleted: %d\n",Ci,Ci->getCount(),j); Ci = Ci->getNext(); clusterCount--; delClus->mergeClosest(clusterList); continue; }else if(Ci->getCount() > i){ i = Ci->getCount(); } Ci = Ci->getNext(); } //HeapDestroy(delLists.hHeap); convertClustersBitmap(clusterList, &clusImg, imgData); writeConsoleFmt("%d clusters found.\n",clusterCount); //seekDiamonds(&clusImg,clusterList); lastClus = clusterList; //writeConsole(" ID RGB Count Position,Box\n"); while(clusterList != (Cluster*)NULL){ clusterList = clusterList->getNext(); //writeConsoleFmt("%08x (%3d,%3d,%3d) %9d %dx%d,%dx%d",lastClus,lastClus->getTone().red,lastClus->getTone().green,lastClus->getTone().blue, //lastClus->getCount(),lastClus->getLeft(),lastClus->getTop(),lastClus->getRight()-lastClus->getLeft(),lastClus->getBottom()-lastClus->getTop()); lastClus->detectShape(); delete lastClus; lastClus = clusterList; } }
/* Seek highest color. * Create list of clusters whose color is greater than or equal. * Order them by X position order, then by Y order. * Save average X and Z position. * Detect distance between them. * If the distance varies on both X and Y directions, the cluster might not belong to thrust. * * */ void seekDiamonds(LPCLUSIMG clusImg, Cluster* head){ Cluster* thisClus = head; ColorValue maxColor, thisColor; PCLUSLIST clusList, thisItem, lastItem; int count = 0; float minDist, thisDist; minDist = 500.0f; while(thisClus != NULL){ thisDist = getColorDistance(COLOR_WHITE,thisClus->getTone()); if(thisDist < minDist){ count = 1; minDist = thisDist; maxColor.color = thisClus->getTone(); } thisClus = thisClus->getNext(); } //create CLUSLIST items. writeConsoleFmt("Highest color: %3d,%3d,%3d\n",maxColor.color.red,maxColor.color.green,maxColor.color.blue); int xmin, xmax, ymin, ymax; clusList = lastItem = (PCLUSLIST)NULL; thisClus = head; while(thisClus != NULL){ thisColor.color = thisClus->getTone(); if(thisColor.value == maxColor.value){ thisItem = (PCLUSLIST)malloc(sizeof(CLUSLIST)); thisItem->cluster = thisClus; thisItem->next = NULL; thisItem->left = thisClus->getLeft(); thisItem->top = thisClus->getTop(); thisItem->width = thisClus->getRight()-thisClus->getLeft(); thisItem->height = thisClus->getBottom()-thisClus->getTop(); thisItem->count = thisClus->getCount(); if(clusList == NULL){ clusList = thisItem; xmin = thisItem->left; xmax = thisItem->left; ymin = thisItem->top; ymax = thisItem->top; }else{ lastItem->next = thisItem; if(thisItem->left < xmin) xmin = thisItem->left; if(thisItem->left > xmax) xmax = thisItem->left; if(thisItem->top < ymin) ymin = thisItem->top; if(thisItem->top > ymax) ymax = thisItem->top; } lastItem = thisItem; } thisClus = thisClus->getNext(); } lastItem = clusList; while(lastItem != NULL){ writeConsoleFmt("Cluster: %08x. Left: %d\n",lastItem->cluster,lastItem->left); lastItem = lastItem->next; } writeConsoleFmt("Variation: x:%d(%d-%d); y:%d(%d-%d);\n",xmax-xmin,xmax,xmin,ymax-ymin,ymax,ymin); clusList = lastItem = bubbleSortList(clusList,lastItem); while(lastItem != NULL){ writeConsoleFmt("Cluster: %08x. Left: %d. DistNxt: %d\n",lastItem->cluster,lastItem->left, (lastItem->next!=NULL?lastItem->next->left-(lastItem->left+lastItem->width):0)); clusList = lastItem; lastItem = lastItem->next; free(clusList); } }
//void Cluster::mergeClosest(Cluster* head, HANDLE hHeap){ void Cluster::mergeClosest(Cluster* head){ int i, j, n, sizex, sizey, step, currCnt, maxCnt, maxWeight, maxDist; Cluster **thisPx, *Ci; LPPIXCNT pixCnt; thisPx = (Cluster**)clustImage->pixClus; thisPx += (top*clustImage->width+left); sizex = right-left; sizey = bottom-top; step = clustImage->width-sizex; maxCnt = 128; maxDist = 0; currCnt = 0; //pixCnt = (LPPIXCNT)HeapAlloc(hHeap,HEAP_ZERO_MEMORY,maxCnt*sizeof(PIXCNT)); pixCnt = (LPPIXCNT)malloc(maxCnt*sizeof(PIXCNT)); i = top; while(i < bottom){ j = left; while(j < right){ if(*thisPx == this){ Cluster* neighbour; for(int c = 0; c < 4; c++){ switch(c){ case 0: //Top if(i == 0) continue; neighbour = *(thisPx-clustImage->width); break; case 1: //Left if(j == 0) continue; neighbour = *(thisPx-1); break; case 2: //Botton if(i+1 == clustImage->height) continue; neighbour = *(thisPx+clustImage->width); break; case 3: //Right if(j+1 == clustImage->width) continue; neighbour = *(thisPx+1); break; } bool found = false; if(neighbour == this) continue; for(n = 0; n < currCnt; n++) if(pixCnt[n].cluster == neighbour){ pixCnt[n].count++; found = true; break; } if(!found){ if(currCnt+1 >= maxCnt){ maxCnt += 128; //pixCnt = (LPPIXCNT)HeapReAlloc(hHeap,HEAP_ZERO_MEMORY,pixCnt,maxCnt*sizeof(PIXCNT)); pixCnt = (LPPIXCNT)realloc(pixCnt,maxCnt*sizeof(PIXCNT)); //writeConsoleFmt("List reallocation. %d current items. %d max items.",currCnt,maxCnt); } pixCnt[currCnt].cluster = neighbour; pixCnt[currCnt].count = 1; pixCnt[currCnt].distance = (int)trunc(getColorDistance(avgTone,neighbour->avgTone)); pixCnt[currCnt].distance = abs(pixCnt[currCnt].distance); if(pixCnt[currCnt].distance > maxDist) maxDist = pixCnt[currCnt].distance; currCnt++; } } } thisPx++; j++; } thisPx += step; i++; } i = 0xFFFFFFFF; maxWeight = 0; for(n = 0; n < currCnt; n++){ int thisWeight = pixCnt[n].count*(maxDist-pixCnt[n].distance); if(thisWeight > maxWeight || pixCnt[n].distance-maxDist < 1.01){ i = n; maxWeight = thisWeight; } //writeConsoleFmt("%08x: %d, %d.\n",pixCnt[n].cluster,pixCnt[n].count,pixCnt[n].distance); } if(i != 0xFFFFFFFF) Ci = pixCnt[i].cluster; else{ Ci = (Cluster*)NULL; writeConsoleFmt("FAILED TO FIND CLOSEST CLUSTER FOR %08X.\n",this); } writeConsoleFmt("Merge %08x (%d,%d,%d) with %08x (%d,%d,%d)\n",Ci,Ci->avgTone.red,Ci->avgTone.green,Ci->avgTone.blue,this,avgTone.red,avgTone.green,avgTone.blue); //HeapFree(hHeap,0,pixCnt); free(pixCnt); if(Ci != (Cluster*)NULL) Ci->mergeCluster(this,head); }