레이블이 영상처리인 게시물을 표시합니다. 모든 게시물 표시
레이블이 영상처리인 게시물을 표시합니다. 모든 게시물 표시

2018년 12월 4일 화요일

Kaggle Competition Quick Draw Solution

You may not be interested, but our 24th solution is below.
1. data generate
2. Model
3. optimize, loss, etc
4. ensemble


1. data generate
 - Using simplified file

def draw_cv2_color(raw_strokes, size=256, lw=6, time_color=True):
    img = np.zeros((BASE_SIZE, BASE_SIZE,3), np.uint8)
    for t, stroke in enumerate(raw_strokes):   
        inertia_x = 0
        inertia_y = 0
        for i in range(len(stroke[0]) - 1):
            color = int(255 - 245*(float(t)/len(raw_strokes))) if time_color else 255 ## strokes order
            print(color)
            sx = stroke[0][i]
            sy = stroke[1][i]
            ex = stroke[0][i + 1]
            ey = stroke[1][i + 1]
            color_v =  (np.sqrt((sx-ex)*(sx-ex) + (sy-ey)*(sy-ey)) / np.sqrt(size*size)) * 255 ## strokes distance like speed (1~0)
            color_a = (np.sqrt((inertia_x-ex)*(inertia_x-ex) + (inertia_y-ey)*(inertia_y-ey)) / np.sqrt(size*size*4)) * 255 ## strokes distance like acceleration (1~0)
            _ = cv2.line(img, (sx, sy), (ex, ey), (color,color_v,color_a), lw)
            inertia_x = 2*ex -sx
            inertia_y = 2*ey-sy
           
    if size != BASE_SIZE:
        return cv2.resize(img, (size, size))
    else:
        return img



 - Using raw file

## channel order sequence, speed, acceleration and start point interval time, last stroke last point total drawing time
def draw_cv2_color_new(raw_strokes, size=256, lw=6, time_color=True, last_drop_r = 0.0):
    stx_min, sty_min = 99999, 99999
    stx_max, sty_max = 0,0
    ett=0  # How fast to complete less than 20 seconds
   
    for t, stroke in enumerate(raw_strokes):
        if t == len(raw_strokes) -1:
            ett = int(stroke[2][-1])
        for i in range(len(stroke[0])):
            stx_min = min(stx_min, int(stroke[0][i]))
            stx_max = max(stx_max, int(stroke[0][i]))
            sty_min = min(sty_min, int(stroke[1][i]))
            sty_max = max(sty_max, int(stroke[1][i]))
   
    limit_ett = 20*1000 
    ofs = 15
   
    if int(sty_max-sty_min+2*ofs) > 6000 or int(stx_max-stx_min+2*ofs)  > 6000:
        img = np.zeros((6000,6000,3), np.uint8)
    else:
        img = np.zeros((int(sty_max-sty_min+2*ofs), int(stx_max-stx_min+2*ofs),3), np.uint8)

    for t, stroke in enumerate(raw_strokes):   
        inertia_x = 0
        inertia_y = 0
        pre_st_t = 0
        for i in range(len(stroke[0]) - 1):
            color = int(255 - 245*float(t)/len(raw_strokes)) if time_color else 255 ##  stroke order
            sx = int(stroke[0][i]) - stx_min +ofs
            sy = int(stroke[1][i]) - sty_min +ofs
            st = stroke[2][i]
            ex = int(stroke[0][i + 1])- stx_min +ofs
            ey = int(stroke[1][i + 1])- sty_min +ofs
            et = stroke[2][i+1]
           
           
            time = et-st
            if time ==0:
                time = 1
           
            color_v =  min(int((np.sqrt((sx-ex)*(sx-ex) + (sy-ey)*(sy-ey)) / time)*255.0), 255) ## speed
            color_a = min(int((np.sqrt((inertia_x-ex)*(inertia_x-ex) + (inertia_y-ey)*(inertia_y-ey)) / np.sqrt(time*time))*255.0), 255) ## acceleration (1~0)
            _ = cv2.line(img, (sx, sy), (ex, ey), (color,color_v,color_a), lw)
           
            if i==0:
                color_inter = int((float(et-pre_st_t)/limit_ett)*245)+10
                _ = cv2.circle(img, (sx, sy), lw, (0,0,color_inter), -1) ##interval time
           
            if i==len(stroke[0])-2 and t == len(raw_strokes) -1:
                color_end = int((float(ett)/(limit_ett)*245))+10

                _ = cv2.circle(img, (sx, sy), lw, (0,color_end,0), -1) ##end time
               
            inertia_x = 2*ex -sx
            inertia_y = 2*ey-sy
            pre_st_t=et
           
    return cv2.resize(img, (size, size)) #lw reflects how big the picture is drawn, also the aspect ratio is reflected




2. Model Structure
- Best single model 
 : InceptionResnetV2 (139,139,3) size input  local valid score is  0.9516.
 : using raw file, using 'imagenet' weights, batch size 180

base_model = InceptionResNetV2(input_shape=input_shape, weights='imagenet',include_top= False)
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(1024, activation='rule')(x)
x = Dropout(0.3)(x)
predictions = Dense(340, activation='softmax', name='lastfc')(x)
model = Model(inputs=base_model.input, outputs=predictions)


3. Optimizer, Loss, etc.
 - In first train about 1epoch(50M set) , I used adam and learning rate 0.002,
   categorical cross entropy loss
 - Second train , I used adam accumulation 500 iters and learning rate 0.002,
   categorical cross entropy 10% and top3 loss 90%.
 - I did not have enough time to train to the saturation.

#https://github.com/keras-team/keras/issues/3556
import keras.backend as K
from keras.legacy import interfaces
from keras.optimizers import Optimizer
class AdamAccumulate(Optimizer):
    def __init__(self, lr=0.001, beta_1=0.9, beta_2=0.999,
                 epsilon=None, decay=0., amsgrad=False, accum_iters=1, **kwargs):
        if accum_iters < 1:
            raise ValueError('accum_iters must be >= 1')
        super(AdamAccumulate, self).__init__(**kwargs)
        with K.name_scope(self.__class__.__name__):
            self.iterations = K.variable(0, dtype='int64', name='iterations')
            self.lr = K.variable(lr, name='lr')
            self.beta_1 = K.variable(beta_1, name='beta_1')
            self.beta_2 = K.variable(beta_2, name='beta_2')
            self.decay = K.variable(decay, name='decay')
        if epsilon is None:
            epsilon = K.epsilon()
        self.epsilon = epsilon
        self.initial_decay = decay
        self.amsgrad = amsgrad
        self.accum_iters = K.variable(accum_iters, K.dtype(self.iterations))
        self.accum_iters_float = K.cast(self.accum_iters, K.floatx())

    @interfaces.legacy_get_updates_support
    def get_updates(self, loss, params):
        grads = self.get_gradients(loss, params)
        self.updates = [K.update_add(self.iterations, 1)]

        lr = self.lr
        completed_updates = K.cast(K.tf.floordiv(self.iterations, self.accum_iters), K.floatx())
        if self.initial_decay > 0:
            lr = lr * (1. / (1. + self.decay * completed_updates))

        t = completed_updates + 1

        lr_t = lr * (K.sqrt(1. - K.pow(self.beta_2, t)) / (1. - K.pow(self.beta_1, t)))

        update_switch = K.equal((self.iterations + 1) % self.accum_iters, 0)
        update_switch = K.cast(update_switch, K.floatx())

        ms = [K.zeros(K.int_shape(p), dtype=K.dtype(p)) for p in params]
        vs = [K.zeros(K.int_shape(p), dtype=K.dtype(p)) for p in params]
        gs = [K.zeros(K.int_shape(p), dtype=K.dtype(p)) for p in params]

        if self.amsgrad:
            vhats = [K.zeros(K.int_shape(p), dtype=K.dtype(p)) for p in params]
        else:
            vhats = [K.zeros(1) for _ in params]

        self.weights = [self.iterations] + ms + vs + vhats

        for p, g, m, v, vhat, tg in zip(params, grads, ms, vs, vhats, gs):

            sum_grad = tg + g
            avg_grad = sum_grad / self.accum_iters_float

            m_t = (self.beta_1 * m) + (1. - self.beta_1) * avg_grad
            v_t = (self.beta_2 * v) + (1. - self.beta_2) * K.square(avg_grad)

            if self.amsgrad:
                vhat_t = K.maximum(vhat, v_t)
                p_t = p - lr_t * m_t / (K.sqrt(vhat_t) + self.epsilon)
                self.updates.append(K.update(vhat, (1 - update_switch) * vhat + update_switch * vhat_t))
            else:
                p_t = p - lr_t * m_t / (K.sqrt(v_t) + self.epsilon)

            self.updates.append(K.update(m, (1 - update_switch) * m + update_switch * m_t))
            self.updates.append(K.update(v, (1 - update_switch) * v + update_switch * v_t))
            self.updates.append(K.update(tg, (1 - update_switch) * sum_grad))
            new_p = p_t

            # Apply constraints.
            if getattr(p, 'constraint', None) is not None:
                new_p = p.constraint(new_p)

            self.updates.append(K.update(p, (1 - update_switch) * p + update_switch * new_p))
        return self.updates
    def get_config(self):
        config = {'lr': float(K.get_value(self.lr)),
                  'beta_1': float(K.get_value(self.beta_1)),
                  'beta_2': float(K.get_value(self.beta_2)),
                  'decay': float(K.get_value(self.decay)),
                  'epsilon': self.epsilon,
                  'amsgrad': self.amsgrad}
        base_config = super(AdamAccumulate, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))

4. Ensemble
- I used weighed average ensemble by local valid score and argmax corr.
- I used InceptionResNetV2 (raw, simple), Xception (raw), Resnet50 (simple).
- I did not have time to train both (raw, simple)
- Average weight calculation is below code

def get_score_w(local_score):
    ls = np.array(local_score)
    sub = ls - ls.min()
    div = sub/sub.max()
    add = div + 0.1
    nor = add/add.max()
    sqr = nor*nor
    print(sqr)
    return sqr

def get_corr_w(clsnp):
    corxlist=[]
    for idx1, cls1 in enumerate((clsnp)):
        corylist=[]
        for idx2, cls2 in enumerate((clsnp)):
            cor_max = np.corrcoef(np.argmax(clsnp[idx1],axis=1),np.argmax(clsnp[idx2],axis=1))[0][1]
            corylist.append(cor_max)
        corxlist.append(corylist)

    df = pd.DataFrame(corxlist,columns=names, index=names)
    #print(df)
    corr_w = []
    for i in range(df.shape[0]):
        count = 0
        thr = 0.95
        for v in df.values[i]:
            if v > thr :
                count+=1
        corr_w.append(1.0/count) 
    return np.array(corr_w), df

def getensemble_w(clsnp, local_score):
    score_w = get_score_w(local_score)
    for i in range(score_w.shape[0]):
        if score_w[i]==1.0:
            score_w[i] = 1.2 #max score add 20%
    corr_w = get_corr_w(clsnp)[0]
    ensemble_w = score_w*corr_w
    return ensemble_w


Everybody enjoy the competition~!!






2016년 1월 20일 수요일

MIL 재 설치시 에러

matrox image library 를 재설치하고자 할때 
uninstall 후에도 설치가 안될때가 있다.

regstry 편집창에서 아래 항목을 지워준 후에 재부팅 후 설치하면된다.

hkey_current_user\software\Matrox


2016년 1월 19일 화요일

cuda7.0 visual studio 2015 opencv3.1

 Opencv 3.1 을 cuda 포함으로, vs2015로 컴파일 할때 아래 와 같은 문제가 생긴다.
아직 모두 test해본것은 아니지만 vs2015로 cuda7.0 포함하여 컴파일 할때만 문제가 생겼다.



테스트 해 본것은 두 종류..
1. cuda 를 빼고 vs2015로 할 경우 가능.
2. cuda 6.0, 6.5 포함 vs2010으로 할 경우 가능.

2015년 7월 3일 금요일

Qt 시작하기2 with Visual studio and Opencv

 개발 환경 : visual studio2013, qt5.4, opencv 3.0
1. 아래처럼 새프로젝트 만들기를 클릭하고 Qt5 Project를 생성한다.
 일단 sample test임으로 선택사항은 변경없이 finish


2. 프로젝트 생성후 탐색기를 보면 아래와 같이 파일들이 생겨있다.
이중 *.ui 파일을 클릭 해보면


3. qt designer 가 실행되고 dialog가 보인다.
여기에 버튼하나와 label 하나를 추가했다.

4. 아래 그림처럼 시그널/슬롯 편집버튼을 클릭하여 버튼과 다이얼로그를 연결한다.
그후에 연결설정을 클릭하여 slot에 새로운 함수(여기서는 LoadImage)를 넣는다.
5. 헤더(여기서는 qttest5.h) 파일을 열어 함수를 선언한다.
 수정부분은 검은색 표시부분




  • #ifndef QTTEST5_H
  • #define QTTEST5_H
  • #include <QtWidgets/QMainWindow>
  • #include "ui_qttest5.h"
  • class qtTest5 : public QMainWindow
  • {
  •     Q_OBJECT
  • public:
  •     qtTest5(QWidget *parent = 0);
  •     ~qtTest5();
  • private:
  •     Ui::qtTest5Class ui;
  •      private slots:
  •      void LoadImage();
  • };
  • #endif // QTTEST5_H

  • 6. cpp(여기서는 qttest5.cpp) 파일을 열어 함수를 선언한다.
     수정부분은 검은색 표시부분





  • #include "qttest5.h"
  •  #include "opencv2/opencv.hpp"
  •  using namespace cv;
  • qtTest5::qtTest5(QWidget *parent)
  •     : QMainWindow(parent)
  • {
  •     ui.setupUi(this);
  • }
  • qtTest5::~qtTest5()
  • {
  • }
  •  void qtTest5::LoadImage()
  •  {
  •      VideoCapture cap(0);
  •      Mat img;
  •      cap >> img;
  •      QImage qimg(img.data,    img.cols, img.rows, QImage::Format_RGB888);
  •      ui.label->setPixmap(QPixmap::fromImage(qimg));
  •  }

  • 컴파일 후 실행해보면 아래처럼, ui에 webcam으로 찍은 image가 display된다.




     참고사항 : opencv 빌드시 with qt를 해주어야 한다.
    현재(2015/07/09) 기준으로 opencv 3.0 을 다운로드 후 cmake로 열면 default는 with qt항목이 체크해제 되어있다. 체크 후 빌드가 필요하다. 그리고 qt 경로도 자동으로 찾지 못하였다. 아래 그림처럼 qt 경로들을 찾은후 입력 해주고 Generate를 한 후 다시 빌드해야한다.

    2015년 4월 10일 금요일

    opencv 3.0 에 blob or labeling algorithm 추가 되었다...

     이전 글에서 opencv 에 labeling algorithm이 없어서, 구현해서 사용한다고 했었는데..
    요즘 open source 에 기여를 해보고 싶어서, 만들어서 pull request 해봐야 겠다고 생각했었다.
    github에서 clone해서 시작해보려고 code들을 둘러 보는데 labeling 기능이 추가 되어있었다.
    이름은 익숙한 labeling이나 blob은 아니고 connected_compnents 이다.

    함수 사용은 아래와 같다.
    int cv::connectedComponents(InputArray image,
    OutputArray labels,
    int connectivity = 8,
    int ltype = CV_32S 
    )
    computes the connected components labeled image of boolean image
    image with 4 or 8 way connectivity - returns N, the total number of labels [0, N-1] where 0 represents the background label. ltype specifies the output label image type, an important consideration based on the total number of labels or alternatively the total number of pixels in the source image.
    Parameters
    imagethe image to be labeled
    labelsdestination labeled image
    connectivity8 or 4 for 8-way or 4-way connectivity respectively
    ltypeoutput image label type. Currently CV_32S and CV_16U are supported.

    blob 하고 나서 object 들의 feature들을 추출해야 할 경우가 대부분인데. 그때는 아래 함수를 사용하면 된다.

    int cv::connectedComponentsWithStats(InputArray image,
    OutputArray labels,
    OutputArray stats,
    OutputArray centroids,
    int connectivity = 8,
    int ltype = CV_32S 
    )
    This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
    Parameters
    imagethe image to be labeled
    labelsdestination labeled image
    statsstatistics output for each label, including the background label, see below for available statistics. Statistics are accessed via stats(label, COLUMN) where COLUMN is one of cv::ConnectedComponentsTypes
    centroidsfloating point centroid (x,y) output for each label, including the background label
    connectivity8 or 4 for 8-way or 4-way connectivity respectively
    ltypeoutput image label type. Currently CV_32S and CV_16U are supported.
    실제 algorithm이 어떻게 구현되어있는지 궁금해서 source code 분석중인데.. 어렵다.
    현재 3.0 에 추가된 connectedComponents algorithm은 아래의 paper 이다.

    https://sdm.lbl.gov/~kewu/ps/LBNL-59102.pdf




    connectedComponentsWithStats 에는 blob에 대한 아래의 정보들을 추출해 준다.


    1. //! connected components algorithm output formats
    2. enum ConnectedComponentsTypes {
    3. CC_STAT_LEFT = 0, //!< The leftmost (x) coordinate which is the inclusive start of the bounding
    4. //!< box in the horizontal direction.
    5. CC_STAT_TOP = 1, //!< The topmost (y) coordinate which is the inclusive start of the bounding
    6. //!< box in the vertical direction.
    7. CC_STAT_WIDTH = 2, //!< The horizontal size of the bounding box
    8. CC_STAT_HEIGHT = 3, //!< The vertical size of the bounding box
    9. CC_STAT_AREA = 4, //!< The total area (in pixels) of the connected component
    10. CC_STAT_MAX = 5
    11. };

    blob에 대한 Gray 값 추출이 필요할 때가 많은데.. 그게 없어서 아쉽다.
    아래는 blobImage 로 각 blob의 Gray Sum을 뽑는 함수다.
    각 blob의 gray sum을 area 값으로 나누어서 평균 gray값으로 쓸수 있다.

    1.     Mat Stats;
    2.     Mat Center;
    3.     int nNum = connectedComponentsWithStats(m_BinImg,m_LabelImg,Stats,Center);
    4.     double *pContArray = new double [nNum];
    5.     ExtractObjMeanGray(pContArray,nNum);
    6.     delete [] pContArray;

    1. BOOL CBlobObjectFeature::ExtractObjMeanGray(double *pContArray, int nTotalBlobs)
    2. {
    3.     BOOL bRet = TRUE;

    4.     int nOriginType = m_OrginContImg.type();
    5.     int nLabelType = m_LabelImg.type();

    6.     ///////////////////////////////이부분 필요 없는데. 그냥 놔둔 이유..//////////////////////
    7.     ///////////////opencv3.1에서는 connectedComponents 함수는 0부터 1++ 된 blob 들만 나온다..////////
    8.     ///////////////하지만 다른 library의 blob알고리즘들은 1++가 아닌것이 더 많았다..///////////////////
    9.     /////////////// 혹 바뀔지도 모르거나 다른 lib들과 호환성을 위해 빼지 않았음////////////////
    10.     map<int, int> mapBlobIdx;
    11.     for(int y=0;y<m_LabelImg.rows;y++)
    12.     {
    13.         for(int x=0;x<m_LabelImg.cols;x++)
    14.         {
    15.             if(m_LabelImg.at<int>(Point(x,y))!=0)
    16.             {
    17.                 mapBlobIdx[m_LabelImg.at<int>(Point(x,y))]=0;
    18.             }
    19.         }
    20.     }

    21.     map<int,int>::iterator iter;
    22.     int n=1;
    23.     for(iter = mapBlobIdx.begin();iter!=mapBlobIdx.end();iter++)
    24.     {
    25.         iter->second = n;
    26.         n++;
    27.     }
    28.     ///////////////////////////////////////////////////////////////////////////////////////////////////////////
    29.     ZeroMemory(pContArray,sizeof(double)*nTotalBlobs);
    30.     for(int y=0;y<m_LabelImg.rows;y++)
    31.     {
    32.         for(int x=0;x<m_LabelImg.cols;x++)
    33.         {
    34.             int nLabel;
    35.             double dGray;
    36.             nLabel = m_LabelImg.at<int>(Point(x,y));
    37.             dGray = m_OrginContImg.at<uchar>(Point(x,y));
    38.             pContArray[mapBlobIdx[nLabel]] += dGray;
    39.         }
    40.     }
    41.     
    42.     return bRet;
    43. }