Search

2012年4月29日 星期日

簡易測光錶

    因為有些老相機的測光故障,所以想說弄一組簡單的測光錶方便參考,只要使用一個電壓比較器(LM393)以及三個15k的精密電阻,一個光敏電阻和一個1k的可變電阻即可製作,當然必須要先用現有的相機的測光來參考基準值。



=============2012/06/21===============

    畫成電路洗成板子之後給同學使用,基本上 1/8 ~ 1/1000 秒都非常精準,至於 1/8 秒以下應該選用日製阻體較長的可變電阻就可以量測到了(給同學的只是便宜的台製B類1k可變電阻)。




3D Scanner - wxWidgets+OpenCV

    稍微研究一下外國人的code其實原理是先存一張原圖,之後掃描物件以及攝影機都不能移動,接著開始使用雷射掃描物件,每個frame都要減去原圖因此被雷射照到部份的差值就可以先設定為某一個原色值,接著就可以把那些有被設定為原色值的像素轉為三維座標(物件到鏡頭的距離要自己先輸入),接著可以找出法線以及頂點,並且假設一個相鄰頂點的數量fuzz出空洞部份在render出來模型,然後用八元樹(深度5~8)就可以建立mesh了,而雷射與攝影機還有物件的擺放位置最好程一直線,假設雷射與攝影機之間有個角度,那那個角度將會使該物件另一邊有可能會有相同角度的區塊無法被正確掃描,或者是雷色掃描速度大於攝影機每個frame的更新速度這樣也會有斷層出現,不過可以用一些演算法修補,最後精度當然是跟雷射粗細以及攝影機品質有關了,有時間要繼續修正使用三組掃描器建立出全部面向的模型。





2012年4月14日 星期六

wxWidgets with OpenCV(1)

    最近閒閒去MakerBot看到一個外國人的3D Scanner專案,感覺很有趣研究一下他的source code發現是用wxWidgets加OpenCV寫的,害我突然對OpenCV很有興趣跑去研究一下,基本上要把IplImage結構轉換成wxImage只是BGR轉RGB而已,可以自己寫個函數去轉不然就是用cvConvertImage,然後例如要把Webcam的畫面畫到Panel上就可以用個Timer或是Thread去控制,先貼上Timer的,Thread其實也差不多。



wxCV.h


#include <wx/wx.h>
#include <cv.h>
#include <highgui.h>

enum{
   ID_SCREEN1 = 100,
   ID_SCREEN2,
   ID_START,
   ID_STOP,
   ID_TIMER
};

class App:public wxApp
{
   public:
      bool OnInit();
};

class Frame:public wxFrame
{
   public:
      Frame(const wxString&);
      ~Frame();

   private:
      wxPanel *screen1;
      wxPanel *screen2;
      wxButton *start;
      wxButton *stop;
      wxTimer timer;

      CvCapture *camera;
      IplImage *frame;
      IplImage *temp;
      CvVideoWriter *video_writer;

      void CreateUI();
      void OnPaint(wxPaintEvent&);
      void OnTimer(wxTimerEvent&);
      void OnStart(wxCommandEvent&);
      void OnStop(wxCommandEvent&);
      void OnCapture(wxCommandEvent&);
      void OnExit(wxCommandEvent&);

      DECLARE_EVENT_TABLE()
};


wxCV.cpp


#include "wxCV.h"
/*
 * BGR to RGB
void copy_and_swap_rb(char *s,char *d,int size) {
    const int step = 3;
    char *end = s + size;
    while (s < end) {
        d[0] = s[2];
        d[1] = s[1];
        d[2] = s[0];
        d += step;s += step;   
    }
}

void wx2cv(wxImage &wx,IplImage *ipl) {
    copy_and_swap_rb((char*)wx.GetData(),ipl->imageData,ipl->imageSize);
}

void cv2wx(IplImage *ipl,wxImage &wx ) {
    copy_and_swap_rb(ipl->imageData,(char*)wx.GetData(),wx.GetWidth() * wx.GetHeight() * 3);
}
*/

IMPLEMENT_APP(App)
DECLARE_APP(App)

BEGIN_EVENT_TABLE(Frame,wxFrame)
   EVT_MENU(wxID_EXIT,Frame::OnExit)
   EVT_PAINT(Frame::OnPaint)
   EVT_TIMER(ID_TIMER,Frame::OnTimer)
   EVT_BUTTON(ID_START,Frame::OnStart)
   EVT_BUTTON(ID_STOP,Frame::OnStop)
END_EVENT_TABLE()

bool App::OnInit()
{
   wxFrame *frame = new Frame(wxT("wxCV"));

   frame->Show(true);

   return true;
}

Frame::Frame(const wxString &title):wxFrame(NULL,wxID_ANY,title,wxDefaultPosition,wxSize(800,600),wxMINIMIZE_BOX | wxCLOSE_BOX | wxCAPTION | wxSYSTEM_MENU),timer(this,ID_TIMER)
{
   timer.Stop();

   wxInitAllImageHandlers();

   CreateUI();

   camera = NULL;
   frame = NULL;
   temp = NULL;
   video_writer = cvCreateVideoWriter("video.avi",CV_FOURCC('P','I','M','1'),25,cvSize(640,480),1);
}

Frame::~Frame()
{
}

void Frame::CreateUI()
{
   wxMenu *file = new wxMenu;

   file->Append(wxID_EXIT,wxT("E&xit\tAlt-e"),wxT("Exit"));

   wxMenuBar *bar = new wxMenuBar;

   bar->Append(file,wxT("File"));
   SetMenuBar(bar);

   CreateStatusBar(2);
   SetStatusText(wxT("wxCV"));

   wxBoxSizer *top = new wxBoxSizer(wxVERTICAL);
   this->SetSizer(top);

   wxBoxSizer *screen_box = new wxBoxSizer(wxHORIZONTAL);
   top->Add(screen_box,0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);

   screen1 = new wxPanel(this,ID_SCREEN1,wxDefaultPosition,wxSize(400,500));
   screen_box->Add(screen1,0,wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL,5);

   screen2 = new wxPanel(this,ID_SCREEN2,wxDefaultPosition,wxSize(400,500));
   screen_box->Add(screen2,0,wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL,5);

   wxBoxSizer *button_box = new wxBoxSizer(wxHORIZONTAL);
   top->Add(button_box,0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);

   start = new wxButton(this,ID_START,wxT("&Start"),wxDefaultPosition,wxDefaultSize);
   button_box->Add(start,0,wxALIGN_CENTER_VERTICAL | wxALL,5);

   stop = new wxButton(this,ID_STOP,wxT("&Stop"),wxDefaultPosition,wxDefaultSize);
   button_box->Add(stop,0,wxALIGN_CENTER_VERTICAL | wxALL,5);
}

void Frame::OnPaint(wxPaintEvent &event)
{
   screen1->Refresh();
   screen1->Update();

   screen2->Refresh();
   screen2->Update();
}

void Frame::OnExit(wxCommandEvent &event)
{
   timer.Stop();
   if(frame){
      cvReleaseImage(&frame);
   }
   if(temp){
      cvReleaseImage(&temp);
   }
   if(camera){
      cvReleaseCapture(&camera);
   }
   if(video_writer){
      cvReleaseVideoWriter(&video_writer);
   }

   Close();
}

void Frame::OnStart(wxCommandEvent &event)
{
   camera = cvCaptureFromCAM(-1);

   if(!camera){
      wxMessageBox(wxT("Camera Error!"),wxT("Error"),wxOK,this);
   }
   else{
      timer.Start(40);
   }
}

void Frame::OnStop(wxCommandEvent &event)
{
   timer.Stop();

   if(camera){
      cvReleaseCapture(&camera);
   }
}

void Frame::OnTimer(wxTimerEvent &event)
{
   wxClientDC dc1(screen1);
   wxClientDC dc2(screen2);

   frame = cvQueryFrame(camera);
   temp = cvCreateImage(cvSize(frame->width,frame->height),8,3);
   cvZero(temp);

   cvWriteFrame(video_writer,frame);

   cvConvertImage(frame,temp,CV_CVTIMG_SWAP_RB);

   unsigned char *data;

   cvGetRawData(temp,&data);

   wxImage *image = new wxImage(temp->width,temp->height,data,true);

/*
   wxImage *image = new wxImage(frame->width,frame->height);
   cv2wx(frame,*image);
*/

   wxBitmap *bitmap1 = new wxBitmap(*image);
   wxBitmap *bitmap2 = new wxBitmap(image->ConvertToGreyscale());

   int x,y,width,height;

   dc1.GetClippingBox(&x,&y,&width,&height);
   dc1.DrawBitmap(*bitmap1,x,y);

   dc2.GetClippingBox(&x,&y,&width,&height);
   dc2.DrawBitmap(*bitmap2,x,y);

   delete image;
   delete bitmap1;
   delete bitmap2;
}

g++ -o2 -o wxCV wxCV.cpp `wx-config --cxxflags --libs --unicode` `pkg-config opencv --cflags --libs`


2012年4月3日 星期二

何苦為難字幕組呢

    今天發生一件讓我很賭爛和一件很好笑的事,好笑的那件是小朋友不信邪的故事就不提了,很賭爛的就是標題,其實就是大家都是出自於對作品愛才做義工的,我想沒有"應該"這回事還理所當然這樣,反正我剛剛把以前在某字幕組論壇寫的一些漢化相關的文章都砍了,原本打算要移到這邊的也不想移了,還有我相信團裡的人都是有買原作品的,只是因為看不懂日文才會想一起來把拆出來的腳本漢化方便理解劇情,而不是明明就沒有原作版權,然後上論壇一直靠腰要人幫忙拆腳本幫忙漢化等等的,總之算是有點失望也不想說什麼了。