27 May 2020
|
opencv
ubuntu
conda 환경에서 opencv를 설치했던 기록을 남긴다.
1. 기존 설치 확인
pkg-config --modversion opencv
버전이 출력되지 않고 No package 'opencv' found
가 떠야한다.
2. 기존 버전이 설치되어 있으면 삭제한다.
# 기존 라이브러리 설정파일 및 패키지 삭제
sudo apt-get purge libopencv* python-opencv
sudo apt-get autoremove
#기존설치된 opencv 라이브러리 삭제
sudo find /usr/local/ -name "*opencv*" -exec rm -i {} \;
3. 설치준비
sudo apt-get update
sudo apt-get upgrade
4. opencv 컴파일 위해 필요한 패키지 설치
sudo apt-get install build-essential cmake pkg-config libjpeg-dev libtiff5-dev libpng-dev libavcodec-dev libavformat-dev libswscale-dev libxvidcore-dev libx264-dev libxine2-dev libv4l-dev v4l-utils libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libgtk2.0-dev libgtk-3-dev mesa-utils libgl1-mesa-dri libgtkgl2.0-dev libgtkglext1-dev libatlas-base-dev gfortran libeigen3-dev python2.7-dev python3-dev python-numpy python3-numpy python3.5-dev
5. 4.2.0버전 다운로드
mkdir opencv
cd opencv
wget -O opencv.zip https://github.com/opencv/opencv/archive/4.2.0.zip
unzip opencv.zip
wget -O opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/4.2.0.zip
unzip opencv_contrib.zip
6. 빌드를 위한 디렉토리 생성
cd opencv-4.2.0
mkdir build
cd build
7. 빌드
cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=$(python -c "import sys; print(sys.prefix)") \
-D WITH_TBB=OFF \
-D WITH_IPP=OFF \
-D WITH_1394=OFF \
-D BUILD_WITH_DEBUG_INFO=OFF \
-D BUILD_DOCS=OFF \
-D INSTALL_C_EXAMPLES=ON \
-D INSTALL_PYTHON_EXAMPLES=ON \
-D BUILD_EXAMPLES=OFF \
-D BUILD_TESTS=OFF \
-D BUILD_PERF_TESTS=OFF \
-D WITH_QT=OFF \
-D WITH_GTK=ON \
-D WITH_OPENGL=ON \
-D WITH_GSTREAMER=OFF \
-D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-4.2.0/modules \
-D WITH_V4L=ON \
-D WITH_FFMPEG=ON \
-D WITH_XINE=ON \
-D BUILD_NEW_PYTHON_SUPPORT=ON \
-D BUILD_opencv_python3=yes \
-D OPENCV_GENERATE_PKGCONFIG=YES \
-D PYTHON3_EXECUTABLE=$(which python) \
-D PYTHON3_INCLUDE_DIR=$(python -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())") \
-D PYTHON3_PACKAGES_PATH=$(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") \
-D PYTHON3_NUMPY_INCLUDE_DIRS=$(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")"/numpy/core/include" \
..
- OPENCV_GENERATE_PKGCONFIG: pkg-config에 등록을 자동으로 해준다.
- 마지막 4줄은 현재 conda의 python3 위치를 찾기위한 부분이다.
- 결과가 나올때 마지막 부분에 python3도 빌드가 되었다고 나와야 정상적으로 빌드된 것이고 마지막 3줄 빌드 완료 메시지가 뜬다.
-- Python 2:
-- Interpreter: /usr/bin/python2.7 (ver 2.7.12)
-- Libraries: /usr/lib/x86_64-linux-gnu/libpython2.7.so (ver 2.7.12)
-- numpy: /usr/lib/python2.7/dist-packages/numpy/core/include (ver 1.11.0)
-- install path: lib/python2.7/dist-packages/cv2/python-2.7
--
-- Python 3:
-- Interpreter: /home/petopia-01/anaconda3/envs/dog-detect/bin/python (ver 3.7.7)
-- Libraries: /home/petopia-01/anaconda3/envs/dog-detect/lib/libpython3.7m.so (ver 3.7.7)
-- numpy: /home/petopia-01/.local/lib/python3.7/site-packages/numpy/core/include (ver 1.18.2)
-- install path: /home/petopia-01/anaconda3/envs/dog-detect/lib/python3.7/site-packages/cv2/python-3.7
--
-- Python (for build): /usr/bin/python2.7
--
-- Java:
-- ant: NO
-- JNI: NO
-- Java wrappers: NO
-- Java tests: NO
--
-- Install to: /home/petopia-01/anaconda3/envs/dog-detect
-- -----------------------------------------------------------------
--
-- Configuring done
-- Generating done
-- Build files have been written to: /home/petopia-01/opencv/opencv-3.4.10/build
8. 컴파일 시작
cat /proc/cpuinfo | grep processor | wc -l
- make명령으로 컴파일을 시작한다. 구동머신 스펙에 따라 다르지만 시간이 꽤 걸린다.
- 마지막 16이라는 숫자는 위 명령을 통해 출력된 cpu 코어수를 적어준 것이다.
- time을 사용하여 진행시간이 얼마나 걸렸는지 확인할 수 있다.
9. 컴파일된 결과물 설치
# 컴파일된 결과물 설치
sudo make install
10. 설치 확인
/usr/local/cuda-10.2/targets/x86_64-linux/lib
/usr/lib/x86_64-linux-gnu/libfakeroot
# libc default configuration
/usr/local/lib
# Multiarch support
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
/usr/lib/nvidia-440
/usr/lib32/nvidia-440
/usr/lib/nvidia-440
/usr/lib32/nvidia-440
# Legacy biarch compatibility support
/lib32
/usr/lib32
/usr/local/lib
부분이 출력되는지 확인한다.
- 나오지 않으면 아래 두 줄을 실행한다.
sudo sh -c 'echo '/usr/local/lib' > /etc/ld.so.conf.d/opencv.conf'
sudo ldconfig
참고한 사이트
24 Apr 2020
|
jenkins
ci
ubuntu
굉장히 간단해보이는데 삽질을 오래해서 까먹지 말라고 적어둔다.
- ubuntu jenkins에서
- ssh plugin을 이용해 다른 ubuntu로 접속 후
- 실행중인 process를 port로 검색해서 죽인 후
- nohup으로 새로 띄우는 스크립트이다.
# 1. port(여기서는 5000포트)를 쓰는 processid를 찾아 변수 할당한다.
pid="$(lsof -t -i :5000 -s TCP:LISTEN)";
# 2. processid가 있는 경우에 kill 명령으로 중지시킨다.
if [ "$pid" != "" ]; then
kill -9 $pid;
echo "$pid process kill complete"
else
echo "pid is empty"
fi
cd ~/git/petopia-crawler
# 3. 원하는 새 프로세스를 nohup으로 실행시킨다.
BUILD_ID=dontKillMe DISPLAY=:0 nohup ~/anaconda3/envs/petopia-crawler/bin/python3.7 run.py >> nohup.out 2>&1 &
20 Aug 2019
|
test
python
unittest
pytest
사내에서 프로젝트 진행 중 python flask로 간단한 rest api 서버를 구성할 일이 있었다. 규모가 점점 커지며 유닛테스트가 필요해져 pytest를 사용하여 유닛테스트를 진행했고 간단하게 세팅 및 사용기를 남긴다.
pytest vs unittest
사실은 unittest가 파이썬 표준 테스팅 라이브러리이다. 그러나 구글에서 pytest vs unittest로 검색을 해보면 상당히 많은 포스트가 나오는데, 대부분은 pytest를 추천한다. 이유는 pytest가 unittest와 비교해 사용법이 더 편리하고, 파이썬 스타일 가이드(PEP8)를 따라 간결한 코드 작성에 도움이 되며 테스팅 프레임워크로써의 추가적인 장점(픽스쳐 활용, custom assert 활용)이 있기 때문이라 한다. 특히 django나 flask 등의 프레임워크 위에서 개발하고 있다면 pytest를 활용하는 것이 좋아 보인다.
각각의 비교 글들은 아래를 참고하세요.
- https://www.bangseongbeom.com/unittest-vs-pytest.html
- https://americanopeople.tistory.com/255
- https://www.reddit.com/r/Python/comments/5uxh22/unittest_vs_pytest/
- https://www.slant.co/versus/9148/9149/~unittest_vs_pytest
1. pytest 사용을 위한 설정
우선 pytest 라이브러리 의존성 추가가 필요하다. pip를 통해 설치해준다. 경우에 따라서는 pytest-mock 등 pytest 기반 플러그인 라이브러리를 추가해야 하는 경우들이 생긴다.
인텔리제이의 경우 python test runner 설정을 하면 테스트 수행이 쉬워지고 결과도 인텔리제이 탭에서 확인할 수 있다. Tools > Python Integrated Tools에서 Default test runner를 pytest로 선택한다.
2. 테스트를 작성하기 전에 간단히 알아둬야 할 것들
- pytest에서 test suite으로 인식하는 파일명은 prefix로 test_ 를 붙인다.
- 마찬가지로 test 파일 내에서 생성하는 함수 이름도 prefix로 test_ 를 붙여야 한다.
- 테스트코드를 프로덕트 파일과 분리하여 놓을 필요는 없지만 가독성을 위해서 test 폴더 등을 만들고 그 밑에 몰아넣는 것이 좋다.
3. 샘플 테스트 코드
가장 간단한 형태의 샘플 테스트 코드를 남긴다. contains_whitespace라는 메서드를 테스트하기 위한 코드이다. assert문을 이런식으로 사용한는 정도만 참고하고 자세한 assert문의 사용은 pytest docs를 열어보자.
def test_contains_whitespace_with_valid_input():
result = contains_whitespace('test')
assert result is False
def test_contains_whitespace_with_invalid_input_all_whitespace():
result = contains_whitespace(' ')
assert result is True
def test_contains_whitespace_with_invalid_input_contains_whitespace():
result = contains_whitespace('te st')
assert result is True
4. 테스트 수행
터미널에서는
- pytest test_code.py -k ‘test_method_name’ 명령으로 특정 메서드만 수행하거나
- pytest test_code.py 명령으로 단건 파일을 수행하거나
- pytest ./test_folder 명령으로 특정 폴더 내에 있는 테스트 코드 전체를 수행할수 있다.
인텔리제이에서는 테스트 파일을 우클릭하여 Run ‘pytest …’ 또는 함수 옆에 생기는 초록색 플레이버튼을 통해 실행할 수 있다.
5. mock의 사용
def test_login_with_invalid_user_id(mocker):
mock_response_json = json.dumps({
'data': {
'userId': 'test id',
'password': 'test password'
}
})
mock_response.text = mock_response_json
mock_response.status_code = 400
mocker.patch('requests.post', return_value=mock_response)
result = login_service.login(user_id, password, login_ip)
assert result['userId'] == 'test id'
assert result['loginToken'] == 'test token'
샘플 코드는 requests.post 메서드를 mocker를 통해 mocking하고 login_service의 login 메서드를 테스트하기 위한 코드이다. login_service.login 메서드에는 requests.post 구문이 있을 것이고 그부분이 대체되어 실제로 호출이 되지 않고 return_value에서 정의한 값이 리턴되게끔 수행된다.
mocker를 쓰기 위해서는 우선 pytest-mock이라는 라이브러리가 필요하니 pip를 통해 설치해준다.
- 테스트 메서드에 파라미터로 mocker 를 넣어준다.
- mocking할 대상이 클래스 없는 메서드인 경우는 mocker.patch(‘패키지.파일.메서드명’)
- 클래스 내부의 메서드를 mocking할 때는 mocker.patch.object(클래스, ‘메서드명’)
- return_value 옵션을 활용하여 mock 메서드의 리턴값을 사용자가 정의할 수 있다.
6. 익셉션 발생 여부 테스트
def test_string_to_datetime_with_invalid_input():
with pytest.raises(InvalidFormatException) as ex:
string_to_datetime('some text')
assert ex.value.invalid_fields['key'] == 'some text'
assert ex.value.code == Fail.INVALID_PARAM
assert ex.value.message == 'Invalid format: some text'
위 테스트코드는 InvalidFormatException이라는 익셉션이 발생하기를 기대하고 있다. with 구문 밑에 테스트하고자하는 메서드를 수행시키고, 실제 발생된 익셉션 클래스는 ex.value로 값 검증이 가능하다.
def test_string_to_datetime_with_valid_input():
try:
result = string_to_datetime('2019-01-01T09:00:00')
assert result == datetime.datetime(2019, 1, 1, 9, 0, 0)
except Exception as ex:
pytest.fail(str(ex))
위의 테스트코드는 정상케이스 즉 익셉션이 발생하지 않는 경우에 대한 검증이다. try-except문으로 감싸서, 혹시 익셉션이 발생하는 경우에는 의도적으로 pytest.fail을 호출하는 식이다.
7. fixture의 활용
@pytest.fixture(scope="function")
def login_service():
my_service = ...생략...
return my_service
def test_code(login_service):
result = login_service.login('test id', 'test password')
...생략...
pytest.fixture 구문을 이용하여 test에 필요한 fixture를 미리 준비할 수 있다. 사용하기 위해서 아래의 테스트코드와 같이 파라미터로 fixture 메서드명을 넣어주면 테스트코드 내에서 fixture를 쓸 수 있다.
8. 정리
초반 설정만 대충 잘 해주면 간단한 테스트 코드는 금방 작성되고 쉽게 수행된다. mock의 사용도 어렵지 않다. assert문을 custom하게 만드는 부분은 아직 작성해 보지 않았으나 docs만 봐도 어려워 보이지는 않는다.
9. 링크
05 Jul 2019
|
javascript
codingrule
vue 프로젝트 진행시 coding rule을 정하면서 정리한 글. 핵심은 var를 사용하지 말고 let과 const를 사용하자는 것이다.
var의 문제점
var의 사용은 개발자들에게 javascript 코드를 혼란스럽게 만드는 이유가 된다.
아래는 var 사용으로 나타나는 문제점과 let, const를 사용해야 하는 이유이다.
1. var로 중복 변수를 만들어도 문제없이 동작한다.
var token = "test token";
console.log(token)
var token = "other token"; // 위에서 선언한 test token 값 유실
console.log(token)
javascript의 var 변수는 hoisting이라는 행위를 통해 최상단에 선언이 된다. hoist는 끌어올리기라는 뜻이고 이 행위 덕분에 var 변수는 자바스크립트 엔진 구동시 맨 처음에 선언되는 형태가 된다. 하지만 선언과 동시에 할당된 값이 끌어올려지지 않아서 문제를 발생한다.
만약 이런 코드가 있다고 치자.
console.log(deviceName)
var deviceName = "갤럭시S8";
console.log(deviceName)
위 코드를 엔진이 해석할 때는 아래와 같다.
var deviceName; // 할당된 값은 버리고 선언만 끌어올림
console.log(deviceName)
deviceName = "갤럭시S8";
console.log(deviceName)
위의 코드는 실제로 결과가 어떻게 나올까.
var의 이 호이스팅 동작은 개발자가 코드의 동작을 예측하기 어렵게 만드는 이유가 된다. 이런 var의 호이스팅을 막기 위해서는 자바스크립트 scope 내에(최상단 또는 함수 내부) use strict
을 선언하여 방지할 수 있다. use strict
를 사용하면 호이스팅은 동작하지 않으며 선언되지 않은 변수를 사용한다는 오류를 발생시킨다. let을 사용하면 use strict
선언 없이도 정상적으로 오류가 발생한다.
'use strict'
console.log(deviceName) // error 발생
var deviceName = "갤럭시S8";
console.log(deviceName)
2. var 변수는 scope를 무시한다.
정확히는 var 변수는 function-scoped를 가진다. 이는 다시 말해 function 내부에 var 변수를 가두지 않는다면 global scope를 오염시킬 수 있다는 소리이다.
var token = "test token";
if (token !== null) {
var token = "other token";
console.log(token) // other token
}
console.log(token); // other token
다른 언어들과 달리 자바스크립트의 중괄호 블록 영역 내부(예시의 if)의 var 키워드는 외부 스코프와 고립되지 않는다. 이는 코드 량이 많아지고, 많은 사람들이 함께하는 대규모 프로젝트가 될 수록 소스의 잠재적인 위험도를 높인다.
이를 해결하기 위해 아래와 같이 function 으로 고립시키는 방법이 있다.
(function() {
var token = "test token";
console.log(token);
})();
console.log(token); // error 발생
그런데 여기서도 function에 고립된 변수가 var 없이 선언된다면 자바스크립트는 global 영역에서 변수를 찾아나간다는 것이 문제.
(function() {
token = "test token"; // var 선언 없이 처음 등장
console.log(token);
})();
console.log(token); // test token
위 코드는 개발자의 의도와 상관없이 token 변수를 gloabl scope에 선언되었다.
그럼 어떻게?
3. var 대신 let을 사용하면 된다.
let과 const는 모두 block-scoped 변수로 외부 스코프에 영향을 주지 않는다. 같은 스코프 내에서는 중복된 변수 선언을 당연히 할 수 없고 global scope에 선언된 동일한 이름의 변수는 내부 스코프에 영향을 주지 않는다. (일반적으로 개발자들이 원하던 변수의 스코프 범위)
let token = "test token";
let token = "other token"; // syntax error 발생. ide에서는 모두 compile error로 인식
let token = "test token";
token = "other token"; // 재할당 가능
let token = "test token";
if (utils.isEmpty(user)) {
let token = "other token";
}
console.log(token); // test token, 전역 스코프에 선언된 변수 값 유지
4. const는 값의 재 할당이 불가능하다.
한번 선언되면 값을 재할당 할 수 없는 const의 특성 때문에 상수 선언에 사용되고, 코드 흐름상 추후 값 변경이 없는 변수의 경우는 const로 선언하는 것을 권장한다. 또한 모르는 사이에 코드 진행상 값이 재할당 되는 것을 방지하기 위해 const를 선언하는 습관을 들이는 것을 자바스크립트 개발서에서 추천 하곤 한다.
let은 값 할당 없이 선언만 하는 것이 가능하지만 const는 그렇지 않다는 것에 주의한다.
const REST_URL = "http://localhost:5000/rest";
REST_URL = "other url"; // 값 재할당 시도시 error 발생
const IAM_SERVER_URL; // 값 할당 없이 선언만 하는 경우 error 발생
코드 내에서 const를 상수 용도로 쓰는 경우와 변수 용도로 쓰는 경우를 구분해야 가독성이 높아진다. 일반적으로 상수는 대문자와 언더스코어를 사용하여 작성하고 변수는 카멜케이스로 작성한다. 절대적인 규칙은 아니다.
const RELAY_SERVER_URL = "http://relay-server-url" // 상수 선언
const result = otherService.method(); // 변수 용도로 선언
3줄 요약.
- 이제 var는 쓰지말자.
- 대신에 let과 const를 쓰자.
- 값의 재할당이 없을 것 같다고 여겨지면 const를 쓰는 버릇을 들이자.