[카테고리:] 생활코딩

  • bash 스크립트로 사진정보를 mysql로 업데이트(버전 업)

    기존 파일을 조금 업데이트 했다.

    카톡 등 다른 사람에게 받은 사진에서 정보를 추출할 수 없다. 아쉬운대로 기록한 날을 찾아 기록했다.

           date=$(eval "awk 'BEGIN{FS=\" \";}/DateTimeOriginal/{print \$4}' temp")
            time=$(eval "awk 'BEGIN{FS=\" \";}/DateTimeOriginal/{print \$5}' temp")
    
            #2018-9-29 삽입.
            #파일 중, null로 date가 입력되는 파일에 파일 생성 날자로 강제로 삽입.
            if [ -n $date]
            then
                date=$(ls $CMD -lh --full-time | awk '{print $6}')
                echo "date is", $date
            fi
    
    
            if [ -n $time]
            then
                time=$(ls $CMD -lh --full-time | awk '{print $7}'| cut -d "." -f 1)
            fi
    
            #
    
            #latitudeRef=$(eval "awk 'BEGIN{FS=\" \";}/GPSLatitudeRef/{print \$4}' temp")
            latitude=$(eval "awk 'BEGIN{FS=\" \";}/GPSLatitude/{print \$4}' temp")
            #longitudeRef=$(eval "awk 'BEGIN{FS=\" \";}/GPSLongitudeRef/{print \$4}' temp")
            longitude=$(eval "awk 'BEGIN{FS=\" \";}/GPSLongitude/{print \$4}' temp")
    
  • wordprss jetpack의 self signed certification

    워드프레스가 제공하는 강력한 플러그인 중 하나가 jetpack이다. 설치하고 활성화하면 되는데, https를 야매로 사용하면서 잘 안됐다. 이런 현상이 2013년부터 나왔는데, 아직도 안된다니 한심하다.

    인터넷을 뒤지다 보니, 좋은 해결을 보게 되었다.
    plugin 디렉토리의 경로 하나만 고쳐주면 된다.

  • openface로 얼굴 판별

    openface로 얼굴 판별

    휴대폰으로 사진을 열심히 모았지만, 너무 많아 태그를 입력할 엄두가 나지 않았다. 입력할 때 파일의 정보를 추출하여 데이터 베이스에 정리했다. 언젠가 얼굴을 인식하는 소프트웨어를 응용하여 판별하려고 했는데, 2016년 정도에 개발된 openface를 찾았고 이를 사용하기로 했다. 인터넷의 누군가 좋은 튜토리얼을 (영문)만들었고 이를 많이 참조했다. 또한 openface가 수정없이 그대로 사용할 정도의 완성도를 보여준다. docker 이미지로 제공되는데 바로 사용할 수 있다.

    목표한 4명의 얼굴을 학습시켰고, 이 모델을 기반으로 모든 파일을 분류 했다. 모델을 만들기는 금방인데, 사진에서 얼굴찾기, 그 얼굴이 누구인지는 확인하기 위해서는 많은 시간(내가 가진 PC로 3일..)을 썼다. 얼굴 인식 후 이를 파일로 기록하였고 아래와 같다.

    === /root/picture/사진/20150211_202325.jpg ===
    
    === /root/picture/사진/MyPhoto_0149.jpg ===
    Predict Daewon @ x=2075 with 0.66 confidence.
    
    === /root/picture/사진/20140412_162452.jpg ===
    List of faces in image from left to right
    Predict Minsu @ x=1377 with 0.63 confidence.
    Predict Daewon @ x=1549 with 0.86 confidence.
    Predict Minsu @ x=1780 with 0.60 confidence.
    Predict Daewon @ x=1893 with 1.00 confidence.
    
    === /root/picture/사진/20130219_152444.jpg ===
    Predict Daewon @ x=63 with 0.52 confidence.
    
    === /root/picture/사진/20121208_110821.jpg ===
    
    === /root/picture/사진/사진110702_003.jpg ===
    
    === /root/picture/사진/사진120207_010.jpg ===
    Predict Minsu @ x=732 with 0.59 confidence.
    
    === /root/picture/사진/20140405_160811.jpg ===
    Predict Miae @ x=1288 with 0.99 confidence.
    
    === /root/picture/사진/20140406_085437_ShearesAve.jpg ===
    Predict Daewon @ x=775 with 0.98 confidence.
    
    === /root/picture/사진/20131013_134752_과천동.jpg ===
    
    

    가끔 한 파일에 여러 이름을 기록하는데, 아마 학습하지 않은 인물이 사진에 있기 때문이다. 신뢰도 0.8 미만이면 믿을 수 없다고 판단하여 지웠다. 공백을 지우고, 여러 행을 한 행으로 만들기 위해 다음 python 스크립을 사용 했다. sed를 사용하려 했으나, python이 낫다. docker로 디렉토리를 root 아래에 바로 마운트하여 경로에 root가 포함되었다. vim으로 해당 경로로 모두 변경했다. 데이터베이스에 굳이 신뢰도와 얼굴 위치를 넣지 않아도 되어 모두 지웠다.

    #_*_ coding: utf-8 _*_
    import re
    import sys 
    from signal import signal, SIGPIPE, SIG_DFL
    
    signal(SIGPIPE,SIG_DFL)
    result_file = open('./resultv3.txt','r')
    flag_found_path=False;
    flag_found_prediction=False;
    
    num_lines = sum(1 for line in open('./resultv3.txt'))
    
    for x in range(num_lines):
        context=result_file.readline()
        #path를 찾는부분.
        path = re.compile("=== .* ===")
        searched_path = path.search(context)
    
        #predict를 찾는 부분
        prediction = re.compile("Predict.*")
        searched_prediction = prediction.search(context)
    
        #===로 시작하는 부분. 
        if searched_path != None:
            flag_found_path=True
    
            #간단한 버전.
            path_str = searched_path.group()
            print('\n'+path_str,end=',')
    
        if searched_prediction != None:
    
            predict_str = searched_prediction.group()
            print(predict_str,end=',')
    

    대부분 코드를 stack overflow에서 찾아 사용했다.

    아래와 같은 “파일 경로” 대 “사람 이름”을 만들 수 있다.

    /imageOtherPar/사진/20130225_163915.jpg,미애
    /imageOtherPar/사진/20121224_203050.jpg,채윤
    /imageotherpar/사진/20130926_151133_人大会堂西路.jpg,채윤
    /imageotherpar/사진/20130926_151133_人大会堂西路.jpg,대원
    /imageOtherPar/사진/사진110612_018.jpg,민수
    /imageOtherPar/사진/사진110612_018.jpg,대원
    /imageOtherPar/사진/20130128_212312.jpg,민수
    /imageOtherPar/사진/사진110612_004.jpg,민수
    /imageOtherPar/사진/20150331_131747.jpg,미애
    /imageOtherPar/사진/20150505_142947.jpg,민수
    /imageOtherPar/사진/20150505_141543.jpg,대원
    /imageOtherPar/사진/20140405_160859.jpg,미애
    /imageOtherPar/사진/사진111016_021.jpg,미애
    

    이 파일을 별도 테이블을 만들어 굳이 python으로 mysql에 입력했다.

    #_*_ coding: utf-8 _*_
    import pymysql
    import re
    import sys 
    import datetime
    from signal import signal, SIGPIPE, SIG_DFL
    
    #pipe를 사용하기 위해.
    signal(SIGPIPE,SIG_DFL)
    
    
    
    present = datetime.datetime.now()
    
    print(present.date())
    
    conn = pymysql.connect(host='localhost', user='*****', password='*****',
            db='*****', charset='utf8')
    
    #column을 접근하기 위해 Dictionary cursor 사용
    #curs = conn.cursor(pymysql.cursors.DictCursor)
    curs = conn.cursor()
    
    
    #read path from file
    
    result_file = open('./찾을수있는얼굴v3.txt','r')
    
    num_lines = sum(1 for line in open('./찾을수있는얼굴v3.txt'))
    
    
    #이름을 ID로 변경.
    #민수-2, 미애-9, 대원-10, 채윤-6
    
    
    for x in range(num_lines):
        #한 줄을 읽음.
        context=result_file.readline()
    
        #경로 찾음.
        path = re.compile("\/.*jpg")
        searched_path = path.search(context)
    
    
        #tag 확인.
        #tag_from_file = re.compile("민수|대원|미애|채윤")
        tag_from_file = re.compile("jpg,.*$")
        tag_searched_from_file_tmp = tag_from_file.search(context)
    
        if tag_searched_from_file_tmp != None:
            #print(tag_searched_from_file_tmp.group())
            tmp_start = tag_searched_from_file_tmp.start()
            tmp_end = tag_searched_from_file_tmp.end()
    
            #file에서 찾은 태그.
            tag_searched_from_file = context[tmp_start+4:tmp_end]
            print(tag_searched_from_file)
            #print(type(tag_searched_from_file))
    
    
        if searched_path != None:
            found_path = searched_path.group()
            print(found_path)
    
        #sql = "select '" + found_path + "' from picture"
        sql = "select * from `picture` where `경로`='"+found_path+"' order by id desc"
        #sql = "insert into `id_with_photo_path`(`id`,`경로`) values (22,'test2/');"
    
        no_tag = 0
        if tag_searched_from_file == "민수" :
            no_tag = 2
        if tag_searched_from_file == "채윤" :
            no_tag = 6
        if tag_searched_from_file == "미애" :
            no_tag = 9
        if tag_searched_from_file == "대원" :
            no_tag = 10
    
        print(type(no_tag))
        print(found_path)
    
        sql = "insert into `id_with_photo_path`(`id`,`경로`,`updated`) values ('"+str(no_tag)+"','"+found_path+"','"+str(present.year)+"-"+str(present.month)+"-"+str(present.day)+"');"
        #sql = """ insert into `id_with_photo_path`(`id`,`경로`) values (%s, %s)"""
    
    
        print(sql)
    
    
        #print("sql is", sql)
        curs.execute(sql)
    
        #rows = curs.fetchall()
    
        #rows는 전체 행을 표시.
        #column을 뽑기 위해 루프로 돌림.
    
        #for row in rows:
    
            #print(type(rows))
            #print(len(rows))
        #    tag=row["태그"]
    
    
            #태그 확인부분.
            #print(tag)
            #rows.strip(",").split(",")
    
    
    #conn.commit()
    
    
    conn.close()
    

    마지막에 conn.commit()을 하지 않으면 sql로 insert를 할 수 없다. 두번 실행을 방지하기 위해 #conn.commit()로 주석처리 했다.

    다음으로 홈페이지에서 파일을 관리하기 위해, 기존에 작성한 사진 조회 페이지를 수정했다. php를 잘 알면 더 고급지게 할 수 있겠으나, 딱 이정도 수준이면 충분하다.

    <?php /* Template Name: myPhotoQuery*/ ?>
    <?php
    get_header(); ?>
    
    <div id="main-content" class="main-content">
    
    <?php
    	if ( is_front_page() && twentyfourteen_has_featured_posts() ) {
    		// Include the featured content template.
    		get_template_part( 'featured-content' );
    
    	}
    ?>
    	<div id="primary" class="content-area">
    		<div id="content" class="site-content" role="main">
    			<?php
    				// Start the Loop.
    				while ( have_posts() ) : the_post();
    
    					// Include the page content template.
    					get_template_part( 'content', 'page' );
    
    
    					// If comments are open or we have at least one comment, load up the comment template.
    					if ( comments_open() || get_comments_number() ) {
    						comments_template();
    					}
    				endwhile;
    			?>
    
    <?php
    //로그인 되었는지  확인하는 부분..
    if( is_user_logged_in())
    {
    	echo '환영합니다.';
    	?>
    <html>
    <body>
    <?php
    	$config = parse_ini_file("****"); 
    
    	$link = mysqli_connect('localhost',$config['user'],$config['passwd']);
    
    	
    	if(!$link)
    	{
    		echo 'Could not connect';
    		echo '<br />';
    		exit;
    	}
    	else
    	{
    		echo '<br />';
    		echo 'Connected<br />';
    		echo '<br />';
    	}
    
    	mysqli_set_charset($link,"utf8");
    	if(!mysqli_select_db($link,'myHome')){
    		echo "could not select DB<br />";}
    	else{
    		echo "data base selected<br />";}
    	
    
    	//한국 시각 기준으로 설정..
    	date_default_timezone_set("Asia/Seoul");
    	$today = date("Y-m-d");
    	$time = time();
    	#echo $time;
    	$minus30Day = date("Y-m-d", strtotime("-30 day", $time));
    	#echo $today;
    	#echo $targetDay;
    
    
    	//처음 접속시 사용자가 입력하는 부분..
    ?>
    	<form method="POST" action="" name="날자 입력">
    	<br><hr>
    	시작 날자
    	<input value=" <?php echo $minus30Day ?>" name="InputStartDay" type="datetime-local" >
    	끝 날자
    	<input value=" <?php echo $today?>" name="InputEndDay" type="datetime-local">
    	<br><br>
    	사람 이름<br>
    	<input value="" name="InputTag"><br>
    	<br><br>
    	표식 개수<br>
    	<input value="10" name="InputLimit" type="number" min="1" max="200">
    	<br><br>
    	
    	선택 완료
    	<input name="submitSelect" type="submit">
    
    	</form>
    
    <?php
    	//선택후 쿼리로 전송..
    	if(isset($_POST["submitSelect"])){
    
    		#InputTag가 누구를 가리키는지 확인.
    		$numbered_person = 0;
    		if ($_POST[InputTag] == '대원') $numbered_person = 10;
    		if ($_POST[InputTag] == '미애') $numbered_person = 9;
    		if ($_POST[InputTag] == '민수') $numbered_person = 2;
    		if ($_POST[InputTag] == '채윤') $numbered_person = 6;
    
    
    		$file_limiter = 50;
    		if( $_POST[InputLimit] > 0 and $_POST[InputLimit] < 1000)
    			$file_limiter = $_POST[InputLimit];
    
    
    
    		#$query="select * from picture where (`종류`='이미지' and (`날자` >= '$_POST[InputStartDay]' and `날자` <='$_POST[InputEndDay]')) limit $_POST[InputLimit]";
    		#
    		#
    		#InputTag가 있을 경우 query.
    		if($numbered_person != 0){
    			$queryCount= "select count(*) from `picture` inner join `id_with_photo_path` on `id_with_photo_path`.`경로`= `picture`.`경로` where (`종류`='이미지' and `picture`.`날자` >= '$_POST[InputStartDay]' and `날자` <='$_POST[InputEndDay]' and `id_with_photo_path`.`ID` = $numbered_person) limit $file_limiter";
    
    			$query ="select * from `picture` inner join `id_with_photo_path` on `id_with_photo_path`.`경로`= `picture`.`경로` where (`종류`='이미지' and `picture`.`날자` >= '$_POST[InputStartDay]' and `날자` <='$_POST[InputEndDay]' and `id_with_photo_path`.`ID` = $numbered_person) limit $file_limiter";
    
    		}
    		
    
    		else {
    			$queryCount="select count(*) from picture where (`종류`='이미지' and (`날자` >= '$_POST[InputStartDay]' and `날자` <='$_POST[InputEndDay]'))";
    
    			$query = "select * from picture where (`종류`='이미지' and (`날자` >= '$_POST[InputStartDay]' and `날자` <='$_POST[InputEndDay]')) limit $file_limiter";
    
    		}
    
    		$resultCount=mysqli_query($link,$queryCount) or die("error");
    
    		while($rowCount=mysqli_fetch_array($resultCount)){
    
    			echo "총 갯수는 ".$rowCount[0];
    		}
    
    
    		echo $query;
    		$result=mysqli_query($link,$query) or die("error");
    		$index=0;
    		while($row=mysqli_fetch_array($result)){
    			$index=$index+1;
    
    
    			?>
    			<div class="layout">
    				<div class="text" align="middle">
    				<br>
    						<?php
    							echo $row['설명']."<br>";
    							echo $row['날자']."<br>";
    							echo $row['태그']."<br>";
    							echo $row['경로']."<br>";
    						?>
    				</div>
    				<div class="polaroid" align="right">
    				<img width="100%" alt="" src=<?=$row['경로']?> >
    				</div>
    			</div>
    	<?php
    			}
    	}
    ?>
    
    </body>
    
    </html>
    	<?php
    }
    else
    {
    	echo '로그인하지 않고는 볼수 없습니다.';
    }
    ?>
    
    
    
    		</div><!-- #content -->
    
    	</div><!-- #primary -->
    
    	<?php get_sidebar( 'content' ); ?>
    
    
    </div><!-- #main-content -->
    
    <?php
    get_sidebar();
    get_footer();
    

    아래 동영상에 나오듯이 조회하는데, 공개 프로그램인지 정확도가 좀 떨어진다. 또한  2018년 이후 찍은 사진을 인식할 수 없다. 해상도를 높여 다시 학습시켜야 할 듯 하다. 이 짓을 완료하기까지 약 일주일정도 걸렸다.

  • gimp python-fu 사용

    gimp를 사용하면, 마우스를 많이 클릭해야 한다. 대부분 노가다인데, python-fu를 사용하면 반복 작업을 대폭 줄일 수 있다.

    필터 메뉴에서 python 콘솔을 열 수 있다. 해당 코드를 테스트할 경우 유용하나, 약간 긴 코드의 경우 script 파일을 만들어 실행함이 편하다. 다른 파일의 탭을 콘솔에 붙일 수 없다.

    코드를 만든 후, 아래 옵션으로 실행이 가능하다. 여기를 참조했다.

    Execute 2: gimp -idf --batch-interpreter=python-fu-eval -b - < save-xcf-to-png-02.py

    • 배치 인터프리터를 python-fu 설정.
    • 입력으로 스크립트 설정.

    아래 참조한 사이트에 있는  save-xcf-to-png-02.py 파일이다.

    # Note required here, see: /usr/lib/gimp/2.0/plug-ins/python-eval.py
    # from gimpfu import *
    from glob import glob
    
    def convert(filename):
      print "Filename: " + filename
      img = pdb.gimp_file_load(filename, filename)
      new_name = filename.rsplit(".",1)[0] + ".png"
      layer = pdb.gimp_image_merge_visible_layers(img, 1)
    
      pdb.gimp_file_save(img, layer, new_name, new_name)
      pdb.gimp_image_delete(img)
    
    for filename in glob("*.xcf"):
      convert(filename)
    
    pdb.gimp_quit(1)
    

    내가 하려는 작업은 2개 점이 찍힌 레이어를 랜덤수치만큼 이동하여 약 100개정도 이미지를 만듦이다. gimp 이미지 원본 파일에 배경, 점이 찍힌 레이어가 있다. 아래와 같이 간단한 코드로 50개를 금방 만들 수 있다.

    #-*- coding: utf-8 -*-
    import random
    from gimpfu import *
    
    #python-fu console에 직접 붙일 수 없어 아래 방식으로 명령어 실행.
    #>> gimp -idf --batch-interpreter=python-fu-eval -b -< !!!!!여기에 파일 이름 입력!!!
    
    i=0
    
    img = pdb.gimp_file_load("/home/now0930/gimpScript/basicForm.xcf","/home/now0930/gimpScript/basicForm.xcf")
    
    
    #점 2개가 찍힌 레이어. 점 2개를 임의의 위치로 이동.
    layer = img.layers[1]
    
    for i in range(1,50):
        x_new = random.randrange(-5,5)
        y_new = random.randrange(-5,5)
        x_off, y_off = layer.offsets
    
        pdb.gimp_layer_translate(layer, x_new-x_off, y_new-y_off)
    
        new_image = pdb.gimp_image_duplicate(img)
        new_layer = pdb.gimp_image_merge_visible_layers(new_image, CLIP_TO_IMAGE)
        i=i+1
        filename = '/home/now0930/gimpScript/Spec2/spec%d.png'%(i,)
        pdb.gimp_file_save(new_image, new_layer, filename,'?')
        pdb.gimp_image_delete(new_image)
    
        #원래 위치로 이동.
        pdb.gimp_layer_translate(layer, x_new+x_off, y_new+y_off)
    

    파일 이름을 입력으로 하는 방법도 있겠지만, 나만 쓸 스크립트이므로, 그냥 직접 경로를 넣었다.

  • tensorflow 1.10 설치기

    아나콘다에 tensorflow를 설치하여 사용했다. 그러나 1.6버전 이후로 tensorflow를 import하면 illegal instruction을 내고 죽었다. 혹시나 해결되었는지 1.10으로 업데이트하여 확인했다. 그러나 역시 같은 문제로 1.5로 다시 돌어왔다.

    검색해 보니, 구글이 제공하는 tensorflow binary 1.6이후 파일이 cpu의 AVX를 기본지원한다. 인텔이 2008년 자사 CPU에 AVX 기능을 적용했다. 불행히도 나는 골동품 투반을 사용한다. CPU를 도저히 교체할 상황이 아니라, 힘들게 컴파일 하기로 했다. 담에는 intel cpu를 쓰리라.

    아래 순서로 작업했다.

      1. nvidia 드라이버 설치. 390버전을 ubuntu 16.04가 지원하지 않아 과감히 패스.
      2. cuda 등 설치. 컴파일하면 다양한 버전을 선택할 수 있다.
      3. tensorRT 설치. 컴파일 하기전 선택할 수 있음.
      4. 매뉴얼에 따라 tensorflow 1.10 컴파일.
      5. virtual environment 사용하여 설치. anaconda에 대해 구글이 알아서 해결하라 주의라, 패스.
      6. 가상 환경에서 activate 후, 내가 컴파일한 tensorflow 설치.

    투반이 6개 코어를 100% 가동하여 5,000초 동안 작업했다.ㅠㅠ