Search

2012年11月20日 星期二

金光戲


    其實我看布袋戲有十幾年了從早期錄影帶(要用一台賽車型到轉機倒轉的那種)看到DVD,不過我都是看霹靂的,但是自從九皇座之後幾檔感覺新鮮感都沒九皇座強,而且那時候剛好升上高中也開始看日本的動畫或者寫程式等等的所以時間上取捨就很少看了,前鎮子就有注意到金光戲要由黃立綱重拍,感覺上年輕一代的出來拍可看性應該很高,而且我也確實被youtube上的宣傳片吸引,趁著上禮拜期中考完順便結案想直接去收決戰時刻1~20,沒想到看了快三十年也是跟我差不多時間沒看布袋戲的叔叔先收了XD,整體來說金光在台語方面我是覺得沒有霹靂標準的感覺而且也有點卡,當然也可能是霹靂看太久先入為主,但有趣的是金光裡面東瀛派系的對話不是跟霹靂一樣只有はいXD,有的片段都會對上很長的日文句子,另外武戲也很多比較不會那麼無聊,但運鏡我覺得霹靂看得比較順,整體來說金光還算不錯看這兩天看了六集XD,話說黑白出場嘴角會上揚有點詭異w

あまい XD


名句w




藏鏡人



表情謎樣的狼XD


2012年11月16日 星期五

Visual CAPTCHA Detection

    幾個禮拜前上課寫個去除背景的demo給人看後沒有在碰了,所以就放上來等哪天想改就有,對於圖形驗證碼感覺上如果背景夠複雜,去除背景的演算法複雜度就很高,至於雜訊一些去除線條的演算法或者濾波可以容易去除常見的雜訊,文字本身扭曲的話可以讓Tesseract之類的OCR Library辨識率降低(即使背景、雜訊完整去除),而一些方法的閾值也是要看情況調整,總結來說個人感覺是背景複雜求平均值不容易,而且可能得將背景分區快去除,但針對設計應該是還是可以去除大部分只是複雜度的問題,但如果文字扭曲變形到一定程度似乎常見OCR Library辨識也不易,所以感覺上文字扭曲是必須的,當然最好還是不要用同系列工具生產的驗證圖片,最好混和多種系列使用,不過沒有試過用ML訓練萬筆樣本測試是否能有效提昇辨識度就是了,這裡這裡有對驗證碼類型的分析。

extractor.h


#ifndef __EXTRACTOR__
#define __EXTRACTOR__

#include<cv.h>
#include<cxcore.h>
#include<highgui.h>

#include <iostream>
#include <map>

class Extractor
{
   public:
      Extractor(char*);
      long Average(); //It depends
      void BackgroundErase(); //It depends
      void ColorFull();
      void NoiseClear(); //It depends
      void Cut();
   private:
      long avg;
      IplImage *image;
};

#endif


extractor.cpp


#include "extractor.h"

Extractor::Extractor(char *name)
{
   image = cvLoadImage(name,1);
}

long Extractor::Average()
{
   cvSmooth(image,image,CV_BLUR);

   avg = 0;

   for(int y = 0;y < 3;++y){
      for(int x = 0;x < 3;++x){
long temp = 0;
temp += image->imageData[y * image->widthStep + (x * 3)] + image->imageData[y * image->widthStep + (x * 3) + 1] + image->imageData[y * image->widthStep + (x * 3) + 2];
avg += temp / 3;
      }
   }


   for(int y = image->height - 1;y > image->height - 4;--y){
      for(int x = 0;x < 3;++x){
long temp = 0;
temp += image->imageData[y * image->widthStep + (x * 3)] + image->imageData[y * image->widthStep + (x * 3) + 1] + image->imageData[y * image->widthStep + (x * 3) + 2];
avg += temp / 3;
      }
   }

   for(int y = 0;y < 3;++y){
      for(int x = image->width - 1;x > image->width - 4;--x){
long temp = 0;
temp += image->imageData[y * image->widthStep + (x * 3)] + image->imageData[y * image->widthStep + (x * 3) + 1] + image->imageData[y * image->widthStep + (x * 3) + 2];
avg += temp / 3;
      }
   }

   for(int y = image->height - 1;y > image->height - 4;--y){
      for(int x = image->width - 1;x > image->width - 4;--x){
long temp = 0;
temp += image->imageData[y * image->widthStep + (x * 3)] + image->imageData[y * image->widthStep + (x * 3) + 1] + image->imageData[y * image->widthStep + (x * 3) + 2];
avg += temp / 3;
      }
   }

   avg /= 36;


   return avg ;
}

void Extractor::BackgroundErase()
{
   long range = 20;

   for(int y = 0;y < image->height;++y){
      for(int x = 0;x < image->widthStep;++x){
long temp = (image->imageData[y * image->widthStep + x] +
      image->imageData[y * image->widthStep + x + 1] +
      image->imageData[y * image->widthStep + x + 2]) / 3;
if(temp  < (avg + range) && temp > (avg - range)){
   image->imageData[y * image->widthStep + x] = image->imageData[y * image->widthStep + x + 1] = image->imageData[y * image->widthStep + x + 2] = 255;
}
      }
   }
}

void Extractor::ColorFull()
{
   for(int y = 0;y < image->height;++y){
      for(int x = 0;x < image->widthStep - 3;x += 3){
long temp = (image->imageData[y * image->widthStep + x] +
      image->imageData[y * image->widthStep + x + 1] +
      image->imageData[y * image->widthStep + x + 2]) / 3;
if(temp > 0){
   image->imageData[y * image->widthStep + x] = image->imageData[y * image->widthStep + x + 1] = image->imageData[y * image->widthStep + x + 2] = 0;
}
      }
   }
}

void Extractor::NoiseClear()
{
   int range = 20;
   IplImage *itemp = cvCreateImage(cvGetSize(image),IPL_DEPTH_8U,3);
   cvCopy(image,itemp);

   for(int y = 0;y < itemp->height;++y){
      for(int x = 0;x < itemp->widthStep - 3;x += 3){
long temp = (itemp->imageData[y * itemp->widthStep + x] +
      itemp->imageData[y * itemp->widthStep + x + 1] +
      itemp->imageData[y * itemp->widthStep + x + 2]) / 3;

long ref =  (itemp->imageData[(y - 1) * itemp->widthStep + x] +
      itemp->imageData[(y - 1) * itemp->widthStep + x + 1] +
      itemp->imageData[(y - 1) * itemp->widthStep + x + 2] / 3)
   +
   (itemp->imageData[(y + 1) * itemp->widthStep + x]  +
    itemp->imageData[(y + 1) * itemp->widthStep + x + 1] +
    itemp->imageData[(y + 1) * itemp->widthStep + x + 1] / 3)
   +
   (itemp->imageData[y * itemp->widthStep + (x + 3)] +
    itemp->imageData[y * itemp->widthStep + (x + 3) + 1] +
    itemp->imageData[y * itemp->widthStep + (x + 3) + 2] / 3)
   +
   (itemp->imageData[y * itemp->widthStep + (x - 3)] +
    itemp->imageData[y * itemp->widthStep + (x - 3) + 1] +
    itemp->imageData[y * itemp->widthStep + (x - 3) + 2] / 3)
   +
   (itemp->imageData[(y + 1) * itemp->widthStep + (x - 3)]  +
    itemp->imageData[(y + 1) * itemp->widthStep + (x - 3) + 1] +
    itemp->imageData[(y + 1) * itemp->widthStep + (x - 3) + 1] / 3)
   +
   (itemp->imageData[(y + 1) * itemp->widthStep + (x + 3)]  +
    itemp->imageData[(y + 1) * itemp->widthStep + (x + 3) + 1] +
    itemp->imageData[(y + 1) * itemp->widthStep + (x + 3) + 1] / 3)
   +
   (itemp->imageData[(y - 1) * itemp->widthStep + (x + 3)] +
    itemp->imageData[(y - 1) * itemp->widthStep + (x + 3) + 1] +
    itemp->imageData[(y - 1) * itemp->widthStep + (x + 3) + 2] / 3)
   +
   (itemp->imageData[(y - 1) * itemp->widthStep + (x - 3)] +
    itemp->imageData[(y - 1) * itemp->widthStep + (x - 3) + 1] +
    itemp->imageData[(y - 1) * itemp->widthStep + (x - 3) + 2] / 3)
   ;

ref /= 8;

if((temp + range) < ref){
   image->imageData[y * image->widthStep + x] = image->imageData[y * image->widthStep + x + 1] = image->imageData[y * image->widthStep + x + 2] = 255;
}
      }
   }
}

void Extractor::Cut()
{
   IplImage *gray = cvCreateImage(cvSize(image->width,image->height),IPL_DEPTH_8U ,1);
   cvCvtColor(image,gray,CV_RGB2GRAY);

   cvCanny(gray,gray,30,90);
   cvSmooth(gray,gray,CV_BLUR);
   cvSmooth(gray,gray,CV_BLUR);
   cvSmooth(gray,gray,CV_BLUR);

   std::multimap<int,CvRect> list;

   CvMemStorage* storage = cvCreateMemStorage( 0 );
   CvSeq* contours = NULL;
   cvFindContours(gray, storage, &contours, sizeof( CvContour ), CV_RETR_LIST,CV_CHAIN_APPROX_NONE);
   for( ; contours != NULL; contours = contours->h_next ){
      CvRect rect = cvBoundingRect( contours, 0 );
      //cvRectangle(image, cvPoint( rect.x, rect.y ),cvPoint( rect.x + rect.width, rect.y + rect.height ), cvScalar(0,0,255), 0 );
      list.insert(std::make_pair(rect.width * rect.height,rect));
   }

   //cvSaveImage("find.jpg",image);

 
   int captcha_numbers = 5;
   std::multimap<int,CvRect> result;
   std::multimap<int,CvRect>::reverse_iterator rit = list.rbegin();
   for(int i = 0;rit != list.rend() && i < captcha_numbers;++rit,++i){
      result.insert(std::make_pair(rit->second.x,rit->second));
   }

   char name[] = "1.jpg";
   std::multimap<int,CvRect>::iterator it = result.begin();
   for(;it != result.end();++it){
      cvSetImageROI(image,it->second);
      cvSaveImage(name,image);
      name[0] += 1;
      //std::cout << it->first << std::endl;
   }
}


main.cpp


#include "extractor.h"

int main(int argc,char**argv)
{
   char *name = argv[1];

   if(name){

      Extractor extractor(name);

      /*************pipeline*************/

      extractor.Average();

      extractor.BackgroundErase();

      extractor.ColorFull();

      extractor.NoiseClear();

      extractor.Cut();
   }
   return 0;
}




針對的樣本:

(這組失敗,7和8被當成同範圍)










2012年11月6日 星期二

累人...

  感覺最近又再重複做去年同樣這個時間在做的事,一直覺得太規律的事情不適合我做,工作也好學校也好太規律就渾身不自在啊啊...前些日子把很久以前寫的繪圖引擎改寫之後先試著做2D ACT遊戲引擎驗證,如果把怪物AI跟物理部分獨立出來用LUA之類的腳本個別設計就可以做任何ACT,等有時間再慢慢來寫另一個3D RPG引擎驗證。



  在沒屋頂買了一個很有趣的東西叫VFD管,整個很漂亮等找人弄到Driver IC再來設計PCB弄個時鐘。



  還有很多東西要學要研究偏偏時間很難把握,其實我自己對時間管理不是很擅長希望到過年前能完成大部分。