프로젝트 오른쪽 클릭 > 속성 > ("프로젝트 이름" 속성 페이지) 에서 구성 속성 > C/C++ > 코드 생성 > 런타임 라이브러리
이걸 맞춰주면 된다.
내가 맞춘 방법으로는
오류에서 MT_StaticRelease 값이 MD_DynamicRelease 뭐 이런식으로 떴었는데 MD_DynamicRelease 쪽꺼가 내 프로젝트꺼고 MT_StaticRelease가 라이브러리 쪽 같아서 그냥 내 프로젝트를 MT_StaticRelease쪽에 맞췄다. 그냥 런타임 라이브러리 설정에서 MD를 MT로 바꾼거
이런식으로
요약하면
'RuntimeLibrary'에 대해 불일치가 검색되었습니다. 'MT_StaticRelease' 값이 'MD_DynamicRelease'(프로젝트 이름.obj에 위치) 값과 일치하지 않습니다.
이럴 때 프로젝트의 속성 페이지에서 구성 속성 > C/C++ > 코드 생성 > 런타임 라이브러리 를 MT로 바꿔주면 끝!
그리고 더 찾아본 것인데.
MT는 정적 라이브러리로 연결해서 dll 파일로 동적으로 연결하지 않고 exe에 다 넣어서 정적으로 실행되게 하고
자신이 QT 프로젝트를 만들 때 사용했던거.. Visual Studio로 했으면 MSVC 2019 이런거..
어쨌든 설치했다면 Qt 버전 (설치 된거) 뭐 이런식으로 뜰꺼다..
내껀 이렇게
그래서 이걸 실행해서 여기에다가 windeployqt "exe 파일 경로" / 예) windeployqt "C:\Users\Deploy\QtProject.exe" 이런식으로 입력하면
엄청난 여러가지 문구가 뜨면서
대충 이거하고 여러가지 dll 파일들을 생성하면서 다른 컴퓨터에서도 구동할 수 있게 파일을 만들어준다..
근데 문제는 엄청 귀찮다.. 그리고 명령어가 생각 안날 때도 있다.
그래서 Visual Studio 경우 설정을 찾아보니
Qt Project Setting > Run Deployment Tool 이 있었다.
이걸 이용하면 될 것 같아.
어차피 테스트는 디버그에서 할꺼라 Release에서 하는 경우는 배포용으로 빌드 할 때 밖에 없기 때문에
구성을 Release로 하고
이런식으로 예로 바꾸니
바로 빌드 하자마자 windeployqt 이 명령어 없이 바로 배포 파일들을 생성해주었다..!
근데.. 자주 테스트로 컴파일 해보는 거에다가 저걸 하는건 않좋을 것 같다.. 너무 느려..
뭐 어쨌든 요약!
3가지 파일이 없는 이유는 배포 툴로 파일들을 생성 안한 것이며 생성을 간편하게 할려면 Visual Studio의 경우 속성 페이지로 가서 구성 속성 > Qt Project Setting > Run Deployment Tool 을 예로 바꿔주면 Release로 빌드 할 때마다 배포 파일로 자동으로 만들어줌!
Configuration.h에서 NOZZLE_TO_PROBE_OFFSET의 일부만 검색해도 나온다.
* +-- BACK ---+
* | [+] |
* L | 1 | R <-- Example "1" (right+, back+)
* E | 2 | I <-- Example "2" ( left-, back+)
* F |[-] N [+]| G <-- Nozzle
* T | 3 | H <-- Example "3" (right+, front-)
* | 4 | T <-- Example "4" ( left-, front-)
* | [-] |
* O-- FRONT --+
*/
#define NOZZLE_TO_PROBE_OFFSET { -41, -9, -0.92 }
으음.. 3D 프린터에서 오토레벨링 센서가 있거나.. 없거나.. 이 설정은 중요한 것 같다.
기본적으로 설정은 되어 있지만.. 프린터마다 다 위치가 다르니 개개인 프린터를 다 설정해주는게 좋을 것 같다 생각되지만.. 역시 귀찮긴 함..
보통 같은 방법이라면 3D 프린터로 값을 찾고 M851 인가..? 그걸 써서 GCode를 보내서 저장하고 그러는데.. 내껀 이상하게 EEPROM에 저장하면 프린터가 터지는지 리붓이 된다.. 그래서 음.. 펌웨어에 직접 박아버려야 한다..
일단 위에 코드의 설정값은 내가 직접 한 것이고.. CR10S 기준으로 BLTOUCH는 저 값을 사용하면 될 듯 하다.. 마지막 Z 값은 각자 달라야 겠지만
어쨌든 저건 노즐이 어디에 위치 해 있는지 알려주는 코드다!
오토레벨링 센서를 달았다면 더더욱 중요한데 자기의 레벨 센서를 베드의 어느 지점을 정확하게 찍을지 선정하는 것이기도 하다..!
그냥 BLTouch하고의 Nozzle의 거리다 직접 자로 측정해도 되고 수동으로 맞춰가면서 맞춰도 되고.. 아무거나 상관없다..!
어쨌든 저걸 잘 설정해야 오토레벨링 할 때 각 점을 잘 찍게 된다.
저거 설정 안하고 하면
각 점을 찍을 때 오토레벨링 센서는 그것보다 왼쪽으로 아마 찍을꺼다. 그냥 노즐 기준으로 찍는 거겠지만.. 뭐
이런 코드가 있다. 그리고 위쪽에 보면 back_color로 0x99가 정의 되어 있는데.. 이걸 보면 대충 알 수 있다. 일단 MFC에서 텍스트 이미지를 생성하면 텍스트 밖은 기본적으로 흰색(255, 255, 255), 텍스트는 검은색(0, 0, 0)이다.이다. 또한 0x99는 153으로 RGB 153 153 153 뭐 이래보면 회색이다. 최대가 255이니.. 그래서 최종적으로 저 코드는 텍스트외의 배경 (153, 153, 153)과 (255, 255, 255) 부분을 제외한 검은색 부분(텍스트 부분)을 가져와 사전에 정의한 RGB색대로 다시 설정하는 방식이다.
이 때문에 이 코드에선 아무리 안티에일리어싱을 한들.. 안티 에일리어싱이 픽셀 사이사이에 텍스트보다 연한 색을 찍는건데 이 것들이 다 제외되면서 결국엔 안티 에일리어싱이 안찍힌다..
그래서 내가 생각한 방식은 안티 에일리어싱의 경우 연한 색도 처리해야하기 때문에 배경색이 바뀔때마다 당연히 글자 색도 변경될테니 배경색을 직접 지정하고 텍스트 색도 직접 지정해서 나중에 배경색만 빼는 것이다. 그러면 결국엔 적용되는건 텍스트의 진한 픽셀부터 연한 픽셀까지이다. 그래서 이 방법으로 코딩한건 뭐 아래에 넣을꺼고
또한 내가 지정한 것 중에 다른 것들도 있지만 ori가 있다. 내가 당시 했을때 오리엔테이션인가 뭔가 하는걸로 줄여서 적은 것 같은데.. 잘 못 지정한 것 같다.
나중에 자기 글에다 쓰고 싶다면... 적어도 링크라도.. 부탁.. (이거 그럼 만든게 2022년 11월 쯤에 만들었으니.. 고등학교 2학년 때 만든거군.. 아 여기 학교 C/C++과목 전혀 없음)
뭐 어쨌든 끄읕!
얼마나 사용해줄진 모르겠지만.. C++은 겁나 복잡해!!
(파이썬은 짧고 쉽던데.. 방식은 이거와 비슷)
2023-03-01 추가
코드에서 RGBScale에 대한 구조체 내용이 없어서 다시 정리하고 구조체에 대한 것도 새로 적습니다.
struct RGBScale {
int r = 0;
int g = 0;
int b = 0;
int rgb = 0;
RGBScale(int r, int g, int b) {
this->r = r;
this->g = g;
this->b = b;
this->rgb = RGB(r, g, b);
}
};
RGBScale(0xFF, 0xFF, 0xFF)로 적으면 되는데 0xFF는 그냥 16진수 이기 때문에 0부터 255 숫자중 원하는 색깔에 맞춰 적으시면 됩니다! 그리고.. 기본적으로 cv::Mat 생성할 때 RGB가 아닌 BGR로 생성하기 때문에 아마 RGB 이미지를 넣어서 적용시키면 색깔이 다르게 나올꺼기 때문에.. 인풋엔 BGR로 넣으시면 됩니다. 수정할려면 아래 적혀있는 코드에서 비트맵을 OpenCV로 바꿔주는 곳에서 b, g, r 적혀있는 것을 r, g, b로 변경하시면 될겁니다. RGBScale를 따로 만든 이유는 그냥 r, g, b도 추출하고 rgb도 출력하고 하기 위함!
아래는 다시 정리해본 코드!
void CPputText(cv::Mat& O_image, cv::String text, cv::Point org, int ori, const char* fontName, int fontWeight, double fontScale, RGBScale textColor, RGBScale bkColor) {
int fontSize = (int)(10 * fontScale);
int width = O_image.cols;
int height = fontSize * 3 / 2;
HDC hdc = CreateCompatibleDC(NULL); //텍스트 이미지를 만들어두는 곳 같은거
HBRUSH hBrush = CreateSolidBrush(bkColor.rgb); //채우는 방식인데 bkColor로 단색으로 채우는거
//텍스트 이미지 크기 정하는거
RECT rect;
rect.left = rect.top = 0;
rect.right = width;
rect.bottom = height;
//비트맵의 구조를 사전에 정의하는 것 크기나 색
BITMAPINFOHEADER header;
ZeroMemory(&header, sizeof(BITMAPINFOHEADER));
header.biSize = sizeof(BITMAPINFOHEADER);
header.biWidth = width;
header.biHeight = height;
header.biPlanes = 1;
header.biBitCount = 24;
BITMAPINFO bitmapInfo;
bitmapInfo.bmiHeader = header;
HBITMAP hbmp = CreateDIBSection(NULL, (LPBITMAPINFO)&bitmapInfo, DIB_RGB_COLORS, NULL, NULL, 0);
SelectObject(hdc, hbmp); //hdc에 적용? 하는 거
FillRect(hdc, &rect, hBrush); //지정한 크기만큼 완전하게 채우는거 (다 채움)
BITMAP bitmap;
GetObject(hbmp, sizeof(BITMAP), &bitmap);
//텍스트 이미지 만들 때 사용할 수 있는 폰트를 생성? 하는 그런거
HFONT hFont = CreateFontA(
fontSize,
0,
0,
0,
fontWeight,
FALSE,
FALSE,
FALSE,
DEFAULT_CHARSET, //한국어나 일본어나 해주게 하는거 (아마)
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
ANTIALIASED_QUALITY, //안티 에일리어싱을 켜주는거
VARIABLE_PITCH | FF_ROMAN,
fontName);
SelectObject(hdc, hFont);
SetTextColor(hdc, textColor.rgb);
SetBkColor(hdc, bkColor.rgb);
//계산을 위해 미리 텍스트의 사이즈 구하는거
SIZE size;
GetTextExtentPoint32A(hdc, text.c_str(), (int)text.length(), &size);
TextOutA(hdc, 0, height / 3 * 1, text.c_str(), (int)text.length()); //이미지에 텍스트 적는거
int posX = (ori == 0 ? org.x : (ori == 1 ? org.x - (size.cx / 2) : org.x - size.cx)); //기준 정하는거 0은 텍스트의 왼쪽 1은 텍스트의 중간 2는 텍스트의 오른쪽
int posY = org.y - (size.cy / 2 + 5);
//비트맵 사진을 OpenCV이미지에 삽입해주는거
unsigned char* _tmp;
unsigned char* _img;
for (int y = 0; y < bitmap.bmHeight; y++) {
if (posY + y >= 0 && posY + y < O_image.rows) {
_img = O_image.data + (int)(3 * posX + (posY + y) * (((bitmap.bmBitsPixel / 8) * O_image.cols) & ~3));
_tmp = (unsigned char*)(bitmap.bmBits) + (int)((bitmap.bmHeight - y - 1) * (((bitmap.bmBitsPixel / 8) * bitmap.bmWidth) & ~3));
for (int x = 0; x < bitmap.bmWidth; x++) {
if (x + posX >= O_image.cols)
break;
if (_tmp[0] != bkcolor.b || _tmp[1] != bkcolor.g || _tmp[2] != bkcolor.r) { //텍스트 이미지의 배경 컬러는 없애기 위한 것, bgr 순서로 하는 이유는 Mat 이미지를 처음에 만들 때 BGR 순이여서
_img[0] = (unsigned char)_tmp[0]; //B
_img[1] = (unsigned char)_tmp[1]; //G
_img[2] = (unsigned char)_tmp[2]; //R
}
_img += 3;
_tmp += 3;
}
}
}
//메모리에서 삭제해주는거 이거 안하면 메모리 계속 사용함
DeleteObject(hBrush);
DeleteObject(hFont);
DeleteObject(hbmp);
DeleteObject(hdc);
}