검색결과 리스트
분류 전체보기에 해당되는 글 465건
- 2026.02.01 [논문 리뷰] 처음 보는 물체도 덥석! 박스 모델링으로 해결하는 로봇의 손동작(Minimum Volume Bounding Box Decompos
- 2026.01.19 GPT가 찾아준 초콜릿의 정석, 런던 메종 사마디(Maison Samadi) 방문기 [2025.10.11]
- 2025.12.08 환승객에게 제공되는 호텔 혜택을 누리지 못했던 중국 정저우 환승여행기[2025.10.03]
- 2025.11.28 Ubuntu로 apt 사용시 SSL 인증서 신뢰 문제 발생시 해결방법
- 2025.10.28 Ubuntu에서 Youtube 동영상 PIP모드에서 다른 창에 의해 화면이 가려질 때 해결방법
- 2025.09.05 TensorRT 10버전 이후 변환된 모델을 C++에서 Inference 수행 방법(enqueueV3 함수 사용법)
- 2025.08.01 Windows 환경에서 Visual Studio Code로 Libtorch 라이브러리를 사용해 Torchscript 실행 프로그램 빌드 및 실행
- 2025.07.02 libtorch_cpu.so: undefined symbo: iJIT_NotifyEvent
- 2025.06.02 Libtorch 이전 버전을 다운로드 하는 방법
- 2025.05.20 티스토리에서 카카오 로그인시 튀어나오는 팝업 광고 삭제 방법
- 2025.04.03 포항 영일만 바닷가를 옆에 두고 - 영일만항선 영일만항역(2025.04.01)
- 2025.03.17 git 사용시 오류 발생 해결 방법 - schannel: next InitializedSecurityContext failed
글
[논문 리뷰] 처음 보는 물체도 덥석! 박스 모델링으로 해결하는 로봇의 손동작(Minimum Volume Bounding Box Decompos
인간에게는 아주 쉬운 '물건 집기'가 로봇에게는 왜 그렇게 어려울까요? 우리가 눈을 감고도 컵을 잡을 수 있는 이유는 컵의 전체적인 '형체'를 이미 알고 있기 때문입니다. 하지만 로봇은 처음 보는 물체를 마주하면 방대한 3D 데이터를 처리하느라 과부하에 걸리곤 합니다.
오늘 소개할 논문은 로봇에게 복잡한 계산 대신 '박스(Box)'라는 아주 단순한 안경을 씌워주는 기술을 제안합니다. 이 기술이 완성되면 로봇은 처음 보는 복잡한 장난감이나 도구도 망설임 없이 덥석 잡아 우리에게 건네줄 수 있게 될 것입니다.
정교함보다 중요한 것은 '속도'와 '단순함'
로봇이 실생활에서 우리를 도우려면 물체를 인식하는 데 몇 분씩 걸려서는 안 됩니다. 기존 연구들은 물체를 아주 정밀한 곡면으로 표현하려 했지만, 이는 계산이 너무 복잡하고 센서의 작은 노이즈에도 쉽게 무너지는 단점이 있었습니다.
이 논문은 "사람도 사과를 잡을 때나 컵을 잡을 때 손의 모양이 크게 다르지 않다"는 점에 주목했습니다. 즉, 물체의 아주 미세한 굴곡보다는 전체적인 '덩어리감'만 알아도 충분히 안정적으로 잡을 수 있다는 것이죠. 그래서 선택한 것이 바로 가장 계산하기 쉬운 '박스' 형태입니다.

왼쪽은 기존 방식대로 물체를 아주 정밀하게 묘사한 모습입니다. 보기엔 좋지만 계산이 너무 무겁죠. 오른쪽은 이 논문이 제안한 방식입니다. 토끼를 하나의 커다란 상자에 넣은 것 같은데, 이것만으로도 로봇은 "아, 이 정도 크기의 물체가 이 방향으로 있구나"라는 것을 즉시 알 수 있습니다.
물체를 박스로 쪼개는 'Fit-and-Split'의 마법
이 논문의 핵심은 물체를 가장 잘 설명하는 박스들의 조합을 찾는 것입니다. 그 과정은 크게 세 단계로 나뉩니다.
① 첫 번째 박스 씌우기 (Fit)
먼저 물체의 모든 점을 포함하는 가장 타이트한 박스 하나를 만듭니다. 이를 위해 \(O(n \log n)\)이라는 매우 빠른 효율을 가진 알고리즘을 사용합니다.
② 그림자를 이용한 분할 (Split)
박스 하나로는 물체의 모양을 다 설명할 수 없으니 이를 적절히 쪼개야 합니다. 이때 3D 공간을 직접 뒤지는 대신, 박스의 각 면에 물체의 그림자를 비추는 방식을 썼습니다. 그림자를 보면 어디를 잘라야 박스 두 개가 물체의 모양을 더 잘 감싸게 될지 한눈에 보이기 때문입니다.

3D 입체를 다루는 건 어렵지만, 종이에 비친 그림자를 다루는 건 쉽습니다. 토끼를 세 방향에서 바라본 그림자를 그리드 위에 뿌려놓은 모습입니다. 이 그림자들의 면적을 계산해서, 어느 지점을 싹둑 잘라야 가장 알짜배기 박스 두 개가 나올지 순식간에 찾아냅니다.
③ 똑똑한 중단 (Stopping Criterion)
무한정 박스를 쪼개는 것이 아니라, "박스를 더 쪼갰을 때 부피가 획기적으로 줄어드는가?"를 따집니다. 만약 더 쪼개도 부피 차이가 거의 없다면(즉, 물체의 모양을 더 잘 설명하지 못한다면) 계산을 멈춥니다. 또한 데이터가 너무 적은 부분은 노이즈로 간주하고 무시하여 안정성을 높였습니다.
실험 결과
이 논문은 이상적인 3D 모델뿐만 아니라, 실제 센서로 얻은 거칠고 불완전한 데이터로도 실험을 진행했습니다.

머그컵, 오리 인형, 전화기 등이 박스들로 쪼개지는 과정입니다. 처음에는 박스 1개였다가 설정값을 조절함에 따라 박스가 늘어나며 물체의 실루엣을 닮아갑니다. 지저분한 실제 카메라 데이터(가장 아래 이미지)에서도 꽤 정확하게 형태를 잡아내는 것을 볼 수 있습니다.
실험 결과, 박스로 요약된 모델을 바탕으로 로봇이 잡을 위치를 정했을 때, 아무 정보 없이 무작위로 잡으려 할 때보다 성공률과 안정성이 비약적으로 향상되었습니다. 특히 노이즈가 많은 실제 환경 데이터에서도 박스 모델은 형태의 뼈대를 놓치지 않고 잘 잡아냈습니다.
이 기술이 가져올 미래: 의미 있는 손길
이 기술의 진짜 매력은 로봇에게 '행동의 의미'를 가르칠 수 있다는 점입니다.
안정적 이동: 물체를 단단히 옮겨야 한다면 가장 큰 박스 부분을 꽉 잡습니다.
섬세한 전달: 사람에게 건네주어야 한다면 물체 끝부분의 가장 작은 박스를 잡아 사람이 잡을 자리를 남겨줍니다.
전시 및 검사: 카메라가 물체를 잘 볼 수 있도록 가장 구석진 박스를 잡습니다.

실제 로봇 손이 물체를 파지하는 시뮬레이션 장면입니다. 그래프의 점들이 우측 상단으로 갈수록 로봇이 물체를 안정적으로 꽉 잡았다는 뜻인데, 박스 모델을 사용한 결과(검은 점)가 무작위 시도(초록 점)보다 월등히 우수함을 보여줍니다.
결론
결국, 복잡한 세상을 단순한 박스들의 조합으로 바라보는 것만으로도 로봇은 훨씬 더 인간답고 효율적으로 일할 수 있게 됩니다. 완벽함보다는 '적당한 단순함'이 실생활 로봇에게 얼마나 큰 힘이 되는지 보여준 흥미로운 연구였습니다.
자세한 내용은 아래의 논문을 읽어주시기 바랍니다.
https://ieeexplore.ieee.org/document/4543434
Minimum volume bounding box decomposition for shape approximation in robot grasping
Thinking about intelligent robots involves consideration of how such systems can be enabled to perceive, interpret and act in arbitrary and dynamic environments. While sensor perception and model interpretation focus on the robot’s internal representatio
ieeexplore.ieee.org
'공대생의 팁' 카테고리의 다른 글
| Ubuntu로 apt 사용시 SSL 인증서 신뢰 문제 발생시 해결방법 (0) | 2025.11.28 |
|---|---|
| Ubuntu에서 Youtube 동영상 PIP모드에서 다른 창에 의해 화면이 가려질 때 해결방법 (0) | 2025.10.28 |
| 티스토리에서 카카오 로그인시 튀어나오는 팝업 광고 삭제 방법 (0) | 2025.05.20 |
| Huggingface에서 데이터셋 다운로드가 계속 끊길때 해결방법 (0) | 2025.01.14 |
| Flask 라이브러리로 이미지를 업로드하고 볼 수 있는 서버 구축하기 (0) | 2024.10.26 |
설정
트랙백
댓글
글
GPT가 찾아준 초콜릿의 정석, 런던 메종 사마디(Maison Samadi) 방문기 [2025.10.11]
안녕하세요! 오늘은 런던에서 아주 특별한 미션을 수행하고 온 이야기를 들려드릴까 합니다. 바로 요즘 가장 핫한 '두바이 초콜릿'을 런던 한복판에서 찾아내는 미션이었죠! (사실 이 글을 쓰는 2026년 시점에서는 두쫀쿠가 유행이지만요)
런던에 여행중이었던 저에게 한국의 친한 친구가 톡을 보냈어요. "런던이면 혹시 그 유명한 두바이 초콜릿 스타일의 수제 초콜릿 구할 수 있는 곳 없어?"라며 간절한 부탁을 하더라고요.
요즘 워낙 인기라 구하기 쉽지 않을 것 같아 고민하다가, 저는 GPT에게 구체적으로 물어보기로 했습니다.
"런던에서 두바이 초콜릿 스타일의 수제 초콜릿을 구할 수 있는 곳 알려줘"
그러자 GPT가 런던 첼시(Chelsea)에 위치한 **'메종 사마디(Maison Samadi)'**를 강력 추천해 주었습니다. 중동의 정통 레시피와 유럽의 고급 초콜릿 기술이 만난 곳이라 친구가 찾는 그 맛을 가장 완벽하게 구현하는 곳이라는 설명과 함께요!
1872년부터 이어온 전통, 2016년 런던에 상륙하다
추천을 받고 찾아보니 이곳은 역사가 정말 깊은 곳이었습니다. 사마디 가문은 무려 1872년 베이루트에서 처음 디저트 사업을 시작했다고 해요. 150년 넘게 대를 이어온 장인 정신이 깃든 곳이죠.
런던 첼시에 이 멋진 부티크가 처음 문을 연 것은 2016년입니다. 오픈한 지 10년이 채 되지 않았지만, 이미 '런던 최고의 초콜릿' 상을 휩쓸며 현지인들이 가장 사랑하는 프리미엄 초콜릿 가게로 자리 잡았습니다.
메종 사마디는 런던에서 가장 우아한 거리 중 하나인 **킹스 로드(King's Road)**에 있습니다. 찾아가는 방법은 크게 두 가지예요.
방법 1. 슬론 스퀘어(Sloane Square) 역에서 걷기 (추천!): 지하철 역에서 나와 킹스 로드를 따라 쭉 걸으면 됩니다. 약 20분(1마일) 정도 소요되는데, 첼시 특유의 예쁜 부티크와 갤러리를 구경하다 보면 금방 도착해요.
방법 2. 사우스 켄싱턴(South Kensington) 역에서 버스 이용: 역 근처에서 버스를 타면 약 10분 내외로 도착할 수 있어 체력을 아끼기에 좋습니다.
주소: 301 King's Rd, London SW3 5EP

King's Road를 걷다 보면 아기자기한 가게들이 눈 앞에 펼쳐집니다

계속 걷다보면 우리가 찾던 초콜릿 가게인 '메종 사마디'를 찾으실 수 있습니다.

가게 안은 오래된 역사를 가진 가게 치고는 모던한 분위기입니다.
"배부를 때까지 드셔보세요" 감동의 시식 경험

매장에 들어서자마자 고급스러운 향기와 친절한 직원분들이 저를 맞이해 주셨습니다.

친구가 찾는 '두바이 초콜릿' 스타일의 피스타치오와 견과류가 들어간 라인을 문의하니, 직원분께서 망설임 없이 시식을 권해주셨어요.

그런데 시식 수준이 정말 남달랐습니다. "이게 시식인가요, 식사인가요?" 싶을 정도로 다양한 종류의 초콜릿을 맛볼 수 있었습니다..

하나하나 맛볼 때마다 입안 가득 퍼지는 고소한 견과류와 진한 초콜릿의 조화에 정말 배가 부를 지경이었답니다.

덕분에 친구에게 줄 선물을 고르는 게 훨씬 쉬워졌어요!

다양한 모양과 종류의 초콜릿들이 있고, 심지어 직원분이 직접 하나씩 건내주기도 해서 입안이 얼얼할 정도로 시식해보았습니다.
구매 후기: "런던에 간다면 무조건 들르세요!"

친구의 요청으로 우연히 GPT를 통해 알게 된 곳이지만, 제가 가본 전세계 초콜릿 가게 중 단연 최고였습니다.

단순히 물건을 파는 곳이 아니라, 시식부터 응대까지 대접받는다는 느낌이 확실히 드는 곳이었어요.

런던 여행 중 현지인들이 열광하는 진짜 초콜릿 맛집을 찾으신다면, 혹은 저처럼 특별한 '두바이 초콜릿'의 풍미를 느끼고 싶으시다면 메종 사마디는 필수 코스입니다. 저는 대만족이었고, 선물 받은 친구도 너무 좋아할 것 같아요!

이번 여행 GPT가 우연히 찾아준 보석같은 초콜릿 가게를 발견할 수 있어 너무 기뻤고 앞으로도 여행 도중에 GPT를 업무 수행시와 같이 적극적으로 사용해보고자 합니다. 어러분들도 GPT를 통해 색다른 여행을 해보시길 바랍니다!
'좌충우돌 여행기 > 해외여행' 카테고리의 다른 글
| 환승객에게 제공되는 호텔 혜택을 누리지 못했던 중국 정저우 환승여행기[2025.10.03] (0) | 2025.12.08 |
|---|---|
| 중국 쿤밍 환승여행기(3) - 창수이 국제공항 출국[2018.12.21] (0) | 2018.12.29 |
| 중국 쿤밍 환승여행기(2) - 쿤밍북부역 전통시장[2018.12.21] (0) | 2018.12.28 |
| 중국 쿤밍 환승여행기(1) - 쿤밍 지하철 타고 시내 나가기[2018.12.21] (0) | 2018.12.27 |
| 요코하마스터디움에서 공연관람기 - TUBE LIVE AROUND SPECIAL 2018(2)[2018.08.25] (0) | 2018.09.03 |
설정
트랙백
댓글
글
환승객에게 제공되는 호텔 혜택을 누리지 못했던 중국 정저우 환승여행기[2025.10.03]
이 포스팅의 일부 이미지는 생성형AI를 활용하였음을 알려드립니다.
이번 글은 제가 정저우 경유 중 숙박 제공 절차를 제대로 확인하지 않아 겪게 된 난처한 경험을 기록한 내용입니다. 혹시 중국남방항공을 이용해 오버나잇 환승을 계획하고 계신다면, 반드시 중국남방항공 고객센터에 직접 전화하여 숙박 예약 절차를 반드시 확인하시기 바랍니다. 특히 정저우 공항의 경우, 중국남방항공이 숙박 제공에 대한 책임을 일절 지지 않기 때문에 저처럼 당황스러운 상황을 겪기 쉽습니다.
무비자로 더욱 가까워진 중국, 하지만...

한때 중국 여행은 쉽지 않은 도전이었습니다. 불과 십여년전만 해도 열악한 위생, 어려운 언어, 해외 여행객을 위한 관광 인프라 부족, 심지어 위조지폐가 시중에서 대놓고 통용되는 등 배낭여행으로서 중국을 누비기가 결코 쉽지 않았습니다. 다행히도 시간이 지나면서 중국의 경제 발전으로 중국 정부가 관광산업 투자로 외국인 관광객을 신경쓸 여유가 생기면서 이전보다는 중국 배낭여행의 난이도가 많이 낮아졌습니다. 특히, 중국 전 지역에서 알리페이, 위챗페이 등과 같은 간편결제 시스템이 대중화되며 시중에 대놓고 통용되던 위조지폐 문제가 단숨에 해결되었을 뿐만 아니라, 알리페이 앱내에 번역 기능, 대중교통카드까지 제공되어 지하철 및 버스 탑승이 가능해 외국인의 이동이 한층 더 편해졌습니다.
그럼에도 불구하고 중국 정부의 폐쇄적인 외교 정책으로 인해 까다로운 비자 절차와 복잡한 서류 준비는 많은 이들에게 중국을 '가까운 듯 먼 나라'로 만들었습니다. 특히 한국인 여행자들도 단기 관광이라도 반드시 비자를 받기 위해 현지인의 초청장이나 여행 계획서 등의 서류를 준비해야 했기에, 짧은 일정의 여행조차 부담스러운 절차들이었습니다. 그렇기에 단지 대한민국 여권만 있으면 언제든지 다녀올 수 있는 옆나라 일본과 비교했을 때 무비자 정책이 여행 일정에 상당한 영향을 주는 요소임을 부정할 수 없습니다. 저 역시 어학연수 목적의 비자를 받았을 때를 제외하면, 환승을 위해 잠시 베이징에 들렸던 것이 거의 유일한 중국 방문 경험이었을 정도였습니다.

그러던 중, 2024년 11월 8일부로 중국 외교부가 대한민국을 포함한 9개국에 대해 무비자 입국을 허용하면서 상황이 크게 바뀌었습니다. 비록 입국 심사 과정에서 환승 목적의 입국이라 하더라도 숙소를 예약하지 않았거나, 관광 목적이 불분명하다고 입국심사관이 판단하게 되면 입국을 거부당하는 사례가 종종 있었습니다만, 과거에 비하면 여행 준비가 훨씬 단순해졌습니다.
이 변화 속에서 저는 이번 추석 연휴를 맞아 영국 여행을 계획고, 검색 도중 눈에 들어온 노선이 바로 중국남방항공의 정저우(鄭州) 경유 항공편이었습니다. 무려 17시간 장시간 환승이었지만, 공식 홈페이지에서 정저우 환승객에게 무료 호텔 제공이 가능하다는 안내를 확인하고 자연스레. '이번 기회에 정저우에 잠깐 들렀다 가는 김에 시내구경을 해 볼 수 있겠구나' 하며 기대를 품게 되었습니다.
하지만 현실은 제 기대와 전혀 달랐습니다. 정저우 공항에 도착한 순간부터 저는 복잡하고 불친절한 절차, 모호한 안내, 언어장벽이라는 삼중고와 마주하게 되었고 결국 무료 숙소는 이용하지 못한 채 당황스러운 영국 여행 일정을 시작하게 되었습니다.
이 글은 그 당황스러웠던 순간들에 대한 기록입니다. 특히 앞으로 중국을 경유하여 여행을 계획하시는 분들께는 환승 무료 숙박 서비스는 반드시 사전에 직접 확정 받아 두시기 바란다는 중요한 팁을 전해드리고 싶습니다. 정저우공항에서 환승 계획이 있으신 분께서는 중국남방항공 공식 홈페이지에서 안내된 현지 전화번호로 직접 연락하여 호텔명과 주소, 전화번호를 반드시 확인하시고, 공항 도착 후 이동해야 할 위치도 반드시 확정받으시기 바랍니다!
중국 항공사의 '저렴한 환승'에는 이유가 있다

여행 비용에서 항공권이 차지하는 비중은 상당합니다. 특히 유럽이나 미주 같은 장거리 여행에서는 더욱 그렇습니다. 그래서 중국 항공사들의 저렴한 경유 항공권은 많은 여행자들에게 매우 매력적으로 보입니다. 최근에는 '싼 게 비지떡'이라는 이미지를 벗고 서비스 품질도 상당히 개선되어, 저 또한 긍정적인 마음으로 중국남방항공을 선택했습니다.
특히 이번에 선택한 항공권은 직항 대비 절반도 안되는 가격이었고, 중간 경유지인 정저우에서 하룻밤을 보내면 장거리 비행도 훨씬 수월할 것이라 생각했습니다.
중국남방항공 홈페이지에서도 정저우 경유객에게 무료 숙박 제공을 안내하고 있었기에 더욱 기대가 컸습니다. 하지만 세부 절차를 살펴보던 중, 베이징•상하이•광저우 등 주요 경유 도시는 무료 숙박 신청 방식이 상세히 적혀있었음에도 정저우의 경우 '하루 전 현지 연락처로 문의'하라는 내용만 적혀 있었습니다.
그래도 혹시나 싶어 중국남방항공 고객센터에 전화했더니 상담사는 믿기 어려운 답변을 하였습니다.

"고객님 죄송합니다. 정저우 공항의 경우 중국남방항공에서 제공하는 것이 아니라 현지 공항에서 운영하는 제공하는 것이기 때문에 예약을 도와드릴 수 없습니다."
이게 무슨 소리지? 자신들의 웹사이트에서는 정저우 환승객에게 무료 숙소가 제공된다 해놓고 숙소 예약은 고객이 직접 알아서 해야한다니 너무 무책임한게 아닌가? 중국남방항공의 이러한 답변에 실망한 저는 공식 홈페이지에 안내되어 있던 중국 현지 전화번호로 직접 연락을 해보았는데..
"你好?"
세상에나. 해당 웹페이지에서는 해외 환승객을 대상으로 연락을 받을텐데 숙소 예약을 담당하는 직원이 중국어로 응대하는 것이었습니다. 영어로 소통을 시도하였으나 나의 짫은 영어 실력으로 인해 상대방과 소통이 너무나도 어려워 결국 에이닷전화의 AI 통역 전화 기능을 활용하여 다시 통화를 시도하였습니다.
"안녕하세요. 정저우공항에서 환승 대상자에게 숙소를 제공한다고 해서 연락드리게 되었습니다."
에이닷전화를 통해 나의 한 마디가 끝나면 잠시후 에이닷 전화를 통해 중국어로 상대방에게 전달이 되고, 직원이 중국어로 발언을 이어서 하면 잠시후 해당 대화를 한국어로 들려주는 식으로 진행되었습니다. 지난번처럼 영어로만 소통하였을 때 보다는 그나마 소통이 좀 더 수월하게 이어질 수 있었습니다.
저는 현지 직원과 통화하여 다음과 같은 사실을 확인하였습니다.
- 내 항공 일정은 호텔 제공 대상에 해당됨
- 공항 도착 후 A번 출구로 오면 직원이 안내해 줄 것임
- 하지만 숙소 정보(호텔명, 주소, 전화번호)를 미리 알려주지 않음
여기서 저는 중대한 실수를 하고맙니다. 중국 입국시 환승객도 입국 카드에 머물 숙소와 주소, 전화번호를 반드시 적어야 입국 심사 통과가 가능하다는 사실을 몰랐던 것이었습니다.
정저우 공항에 대한 정보가 워낙 없던데다가 그나마 찾은 정보도 6년전 코로나19가 확산되기 직전이었던 2019년 12월 당시의 글 하나 뿐이었습니다. 이 글에서는 아무런 준비 없이 공항에 도착하였더니 직원들이 환승객들을 데리고 호텔로 데려갔다는 내용이 적혀있었습니다.
https://m.blog.naver.com/sooparkeg/221790618532
[19'런던] 연말 런던 여행, 정저우 환승호텔 및 신정공항
2019.12 영국 런던 12월 런던 여행 정저우 신정공항 경유, 공항 제공 호텔 이용 12월 말부터 1월 초까지 갔...
blog.naver.com
위 글을 참고하며 "도착하면 알아서 안내해주겠지"라고 생각한 것이 화근이었습니다.
그렇게 저는 인천공항에 왔고, 중국남방항공 체크인카운터에서 정저우공항에서 숙소 제공이 되는지 재차 확인하였습니다. 직원은 가능하다는 말 한마디만 하였고, 저는 일단 공항에 도착하면 안내해주는 직원이 있으리라 생각하고 비행기를 타게 되었습니다.

그렇게 정저우신정국제공항에 도착 후, 입국 카드 검토를 받던 중 공항 직원에게서 충격적인 얘기를 들었습니다.

환승객도 체류지가 없으면 입국이 불가능하다고요???
지금까지 중국에 몇 번 입국했던 경험대로 임시 입국 허가를 받았어서 환승객이면 다 들여보내줄 것으로 기대하고 온 것이었는데.. 분명 나처럼 환승 목적으로 정저우공항에 온 승객들도 많이 있을텐데 나 같은 다른 사람들 중에 나처럼 난처한 상황에 처한 승객은 없는걸까?
순간 머릿속이 새하얘졌지만, 입국심사를 기다리던 분들 중에 전화로 숙소를 예약 확정하였다는 다른 승객의 도움으로 임시 주소를 적어 입국은 가까스로 통과했지만, 이미 안내받았어야 했던 정보가 사전에 제공되지 않았다는 사실에 깊은 당혹감을 느꼈습니다.

그렇게 입국심사를 간신히 마치고 한참을 기다려 위탁수하물을 찾고난 후 공항 밖으로 나왔을 땐 제가 의지했던 "A번 출구 안내 직원"은 어디에도 보이지 않았습니다. 이 때 부터 제 고생이 시작될줄은 꿈에도 몰랐습니다.
정저우 공항에서 들은 청천벽력같은 상황
저는 혹시 제가 출구를 잘못 찾은 건 아닌지, 아니면 전날 통화 내용이 제가 잘못 이해한 건 아닌지 의문이 들었습니다. "혹시 에이닷 통역 앱에서 번역이 애매하게 된 건 아닐까?", "담당자가 충분히 설명해주지 않은 건 아닐까?" 라는 생각이 머릿속을 계속 맴돌았습니다.
공항 곳곳을 서성이며 휴대전화로 비슷한 사례를 검색하고 있을 때, 중국인 한 분이 저에게 다가와 끊임없이 중국어로 말을 걸며 "본인의 택시를 타라"고 제안했습니다..

처음에는 경계심이 들어서 그와 거리를 두었지만, 상황이 너무 답답하다 보니 번역기를 켜서 제 사정을 설명해보았습니다. 그러자 그는 제 이야기를 듣고는 "자기가 도와주겠다"고 말하였습니다.
저는 그 중국인 분에게 "중국남방항공에서 환승객에게 숙소를 제공한다고 들었는데, 혹시 관련 담당자에게 연락할 수 있는지"를 번역기를 통해 설명했습니다. 하지만 이미 시각은 밤 12시를 훌쩍 넘겨 중국남방항공 고객센터는 이미 운영이 종료된 상태였고, 공식홈페이지에 있는 중국어 챗봇도 제가 겪고 있는 '정저우 환승 호텔' 상황에 대한 명확한 답을 주지 못했습니다. 그 중국인 분은 약 30분 정도 제 옆에서 이것저것 도와주려 노력했지만, 결국 뾰족한 해결책을 찾지 못한 채 다른 손님을 찾아 떠나갔습니다.

그제서야 저는 "이제 스스로 숙소를 찾는 수밖에 없다"는 생각을 하게 되었습니다. '공항까지 오면 어떻게든 되겠지'라는 막연한 기대는 이미 완전히 깨져버린 뒤였습니다.
출국 전에 트립닷컴에서 정저우공항 근처 숙소를 둘러보면서 무료 픽업을 제공하는 호텔들을 몇 군데 봐둔 기억이 있어 다시 한 번 검색해 공항과 거리가 가깝고, 24시간 픽업을 지원하고, 프론트에서 영어 응대가 가능하며, 1박 2만원대의 저렴한 숙소 한 곳을 예약했습니다.
예약을 마친 뒤, 저는 앱에서 제공하는 전화 기능을 통해 숙소에 전화를 걸었습니다. 하지만 전화를 받는 직원은 단 한마디도 영어를 하지 못하는 분이었습니다. 직원은 계속 중국어로만 빠르게 말을 이어갔고, 저는 단어 하나 제대로 알아듣지 못했습니다.
이 상태로는 픽업 요청이 불가능하다고 판단한 저는 결국 택시를 타고 직접 숙소로 이동하기로 결정했습니다.
간신히 공항 택시 승강장에 도착해서, 앱으로 예약하였던 숙소의 중국어 주소를 기사님께 보여주었습니다. 기사님은 고개를 끄덕이고 내비게이션을 켠 뒤 출발하였습니다. 하지만 숙소 근처에 도착하자 문제가 생겼습니다. 호텔 위치가 큰 도로와 도로 사이 골목 안쪽에 있다 보니, 내비게이션상으로는 목적지에 도착했는데도 택시는 약 5분 동안 주변만 빙빙 돌 뿐이었습니다.
저는 더 이상 시간을 끌 수 없다고 판단하고 기사님께 여기서 내리겠다고 말한 뒤 요금을 정산하고 하차하였습니다. 그리고 고덕지도를 보면서 어두운 골목 사이를 직접 걸어들어갔습니다. 그렇게 지도상으로 표시된 곳 까지는 어떻게든 도착하였지만, 아무리 주변을 둘러봐도 제가 예약한 숙소 이름의 간판이 보이지 않는 것이었습니다.
고덕지도에 표시된 다른 건물 숙소들의 간판은 환하게 켜져있었고, 지도상 위치는 정확해보였는데 정작 제가 예약한 호텔 이름은 어디에도 보이지 않았습니다. '혹시 건물 내부에 표기가 되어 있나' 싶어 엘리베이터를 타고 각 층을 확인해보았습니다. 다행히도 어느 한 층 안내판에서 제가 예약한 숙소 이름을 발견할 수 있었습니다. 하지만 그 층에 도착해보니 제 눈앞에 펼쳐진 것은 프론트 데스크로 보이는 작은 책상 하나와 굳게 닫힌 객실들 뿐이었습니다. 직원도, 안내문도, 불이 켜진 객실도 보이지 않았습니다.
"분명 방금까지 통화한 사람은 어디 있는 거지??"
저는 다시 한 번 숙소 연락처로 전화를 걸었습니다. 전화를 받은 사람은 여전히 중국어로만 이야기하니, 저는 영어로 어떻게든 상황을 설명하려 했지만 서로의 말이 거의 통하지 않았습니다. '이대로는 도저히 해결이 안 되겠다'고 생각한 저는 다시 1층으로 내려가 건물 밖으로 나오려다가, 우연히 건물 1층 다른 숙소 앞에서 한 할머니가 누군가와 통화하고 있는 모습을 보았습니다.
그런데 통화 도중 할머니가 '한궈런'이라는 말을 하는 것이 제 귀에 들어왔습니다. 저는 직감적으로 '혹시 아까 내가 전화했던 사람이 아닐까'라는 생각이 들었습니다. 잠시 후, 할머니는 저를 향해 손짓을 하며 휴대전화를 제게 건네주었습니다. 저는 얼떨결에 전화를 받았고, 전화 너머에서는 조선족 말투의 상담사가 이렇게 말했습니다.
"안녕하십니까 고객님, 이 숙소에서 고객님을 받으려면 주숙등기를 하여야 하는데, 담당자께서 방법을 몰라서 외국인 숙박을 처리할 수 없다고 합니다."
상황을 보아하니 내가 예약한 숙소는 중국인들이 주로 머무는 숙소이다 보니 담당자가 외국인에 대한 주숙등기를 진행해본 경험이 없다는 것이었습니다. 분명 트립닷컴에 확인했을 때는 외국인 숙박이 가능하다고 언급이 되어 있었으나 실제로는 그렇지 않았던 것이었습니다. 제가 예약한 숙소는 중국인 내국인을 대상으로 하는 소규모 숙소였고 실제로는 외국인 투숙을 처리해본 경험이 없어서 외국인 숙박 시 의무적으로 진행해야 하는 '주숙등기' 절차를 모르는 상태였던 것입니다.
저는 결국 상담사에게 부탁해 해당 숙소 예약을 취소했습니다. 그리고 건물을 나서려는데, 그 할머니가 미안한 마음이 들었는지 제 손에 생수 한 병을 쥐여주며 저를 배웅해 주었습니다.
정신을 차리고 휴대전화를 보니 어느새 시각은 새벽 2시가 되어 있었습니다. 이대로 밖에서 계속 방황할 수는 없다고 생각한 저는 다시 주변을 둘러보았습니다. 마침 바로 옆 건물에 또 다른 숙소가 하나 눈에 들어왔습니다. 로비가 비교적 깔끔해 보였고 프론트 데스크에는 직원이 상주해 있었고 분위기도 방금 전 숙소보다 훨씬 안정적으로 느껴졌습니다. 저는 번역기를 켜서 직원에게 천천히 물어보았습니다.
"한국인(외국인)도 이 숙소에서 투숙할 수 있나요?"
직원은 자신의 휴대전화로 번역 앱을 켜서 제 질문을 확인한 뒤, 번역기를 통해 '투숙 가능하다'고 답해주었습니다. 저는 그 자리에서 바로 트립닷컴 앱을 열어 숙소를 검색했습니다. 이 숙소 이름은 영어 표기가 아니라 한자로만 되어 있어서 찾는 데 조금 시간이 걸렸지만, 직원에게 화면을 보여주며 확인한 끝에 같은 숙소라는 답을 들을 수 있었습니다.
숙소의 가격은 약 4만원 정도였고 객실 컨디션은 한국의 일반적인 4만원대 모텔보다 훨씬 깔끔했습니다. 방 안에는 웰컴 쿠키까지 놓여 있어서, 정신없이 흔들리던 새벽에 작은 위로가 되었습니다. 그렇게 혼란스럽던 마음을 추스리며 씻고 짐을 정리한 뒤 침대에 몸을 눕혔습니다. 그 때가 새벽 3시 즈음이었습니다.

"그래도 오늘 밤을 잘 보낼 수 있는 곳을 확보했다"는 안도감과 함께 저는 다음 날 일정을 위해 서둘러 잠에 들었습니다.

다음 날 아침, 숙소에서 제공하는 간단한 조식을 먹고 방으로 돌아와 잠시 휴식을 취하고 있었습니다. 약 30분쯤 지났을 때, 객실 전화가 울렸습니다. 직원은 중국어로 몇 마디를 했지만, 저는 알아듣지 못했습니다. 정황상 "공항 샌딩 차량이 준비되었으니 내려오라"는 의미인 듯 하여 서둘러 짐을 싸서 로비로 내려갔습니다.

잠시 후 숙소 앞에 호텔에서 운영하는 전기차 한 대가 도착했고, 운전기사는 제 짐을 트렁크에 정성스럽게 실어주었습니다. 그렇게 차에 올라탄 뒤 약 15분 정도 달리자 정저우 공항이 다시 눈앞에 나타났습니다.

런던행 항공편 출발 시간은 오후 2시 10분이었는데, 호텔에서 무려 출발 5시간 전에 공항으로 데려다 준 덕분에 저는 공항 로비에서 체크인 시작까지 약 2시간을 더 기다려야 했습니다. 정저우공항 국제선 출발편은 제가 왔던 시점을 기준으로 단 세 편 정도에 불과해 보였습니다. 대부분은 중국 국내선 항공편이 차지하고 있었고, 그 중에서 런던행 항공편은 약 6년 전 허난성 최초의 유럽 노선으로 개설된 이후 현재까지 유지되고 있는 노선이라 합니다.

어찌 되었든 저는 우여곡절 끝에 정저우에서의 예기치 못한 밤을 마무리하고 무사히 런던 개트윅공항으로 향하는 비행기에 오를 수 있었습니다.
이번 경험이 남긴 교훈
저는 이 경험을 통해 '여행을 떠나기 전 아무리 치밀하게 계획을 세워도 예상치 못한 변수는 언제든지 발생할 수 있다.'는 것을 뼈저리게 느꼈습니다. 그래서 이번 일을 기록하고 공유하는 일이 중요하다고 생각했습니다. 누군가에게는 그저 한 사람의 해프닝처럼 보일 수 있지만, 또 다른 누군가에게는 입국 거절이나 노숙 위기에서 벗어날 수 있는 정보가 될 수도 있기 때문입니다.
특히 정저우처럼 한국어 후기나 정보가 거의 없는 공항을 경유하실 계획이라면 아래 사항을 반드시 체크하시기 바랍니다.
- 환승 무료 숙박은 반드시 사전에 '직접' 전화로 예약 확정
- 입국카드에 적을 호텔 이름, 주소, 전화번호를 미리 준비
- 외국인 투숙이 가능한 숙소인지, 주숙등기 경험이 있는 곳인지 꼭 확인할 것
아이러니하게도, 이런 디테일한 정보는 저처럼 실제로 부딪혀 본 사람만이 알게 되는 경우가 많습니다. GPT나 검색만으로는 쉽게 찾을 수 없었던 내용이기에 저는 이 글을 통해 한 사람이라도 저와 같은 일을 겪지 않으셨으면 하는 마음입니다.
언젠가 누군가가 정저우 환승 관련 내용을 검색하다가 이 글을 발견해 숙소 예약을 확정받으실 수 있다면 그것만으로도 이번 여행의 삽질은 조금은 의미가 생기지 않을까 싶습니다.
'좌충우돌 여행기 > 해외여행' 카테고리의 다른 글
| GPT가 찾아준 초콜릿의 정석, 런던 메종 사마디(Maison Samadi) 방문기 [2025.10.11] (0) | 2026.01.19 |
|---|---|
| 중국 쿤밍 환승여행기(3) - 창수이 국제공항 출국[2018.12.21] (0) | 2018.12.29 |
| 중국 쿤밍 환승여행기(2) - 쿤밍북부역 전통시장[2018.12.21] (0) | 2018.12.28 |
| 중국 쿤밍 환승여행기(1) - 쿤밍 지하철 타고 시내 나가기[2018.12.21] (0) | 2018.12.27 |
| 요코하마스터디움에서 공연관람기 - TUBE LIVE AROUND SPECIAL 2018(2)[2018.08.25] (0) | 2018.09.03 |
설정
트랙백
댓글
글
Ubuntu로 apt 사용시 SSL 인증서 신뢰 문제 발생시 해결방법
Ubuntu 환경에서 apt로 CUDA를 deb 패키지로 설치하기 위해 Nvidia 공식 페이지의 설명대로 key를 등록 후 아래와 같은 명령어를 입력했습니다.
sudo apt update
그런데 아래와 같은 오류가 발생하였습니다.
Certificate verification failed: The certificate is NOT trusted. The certificate issur is unknown
위 에러는 웹에 접근시 SSL 인증서를 확인하는 과정을 거치는데 모종의 사유로 SSL 인증서가 변조되어 신뢰할 수 없는 상황에서 발생하는 메시지입니다. 특히 사내망에서 보안 목적으로 SSL 인증서가 변조되는 경우인데 다음과 같이 명령어를 추가해주면 SSL 인증 확인을 무시하고 apt 명령어를 사용하실 수 있습니다.
sudo apt -o Acquire::https::Verify-Peer=false update
'공대생의 팁' 카테고리의 다른 글
| [논문 리뷰] 처음 보는 물체도 덥석! 박스 모델링으로 해결하는 로봇의 손동작(Minimum Volume Bounding Box Decompos (0) | 2026.02.01 |
|---|---|
| Ubuntu에서 Youtube 동영상 PIP모드에서 다른 창에 의해 화면이 가려질 때 해결방법 (0) | 2025.10.28 |
| 티스토리에서 카카오 로그인시 튀어나오는 팝업 광고 삭제 방법 (0) | 2025.05.20 |
| Huggingface에서 데이터셋 다운로드가 계속 끊길때 해결방법 (0) | 2025.01.14 |
| Flask 라이브러리로 이미지를 업로드하고 볼 수 있는 서버 구축하기 (0) | 2024.10.26 |
설정
트랙백
댓글
글
Ubuntu에서 Youtube 동영상 PIP모드에서 다른 창에 의해 화면이 가려질 때 해결방법
지난 2025년 10월 15일부로 Windows 10 공식 지원이 완전 종료됨에 따라 사용하던 PC의 운영체제를 바꾸어야 하는 상황이 되었습니다. 안타깝게도 제가 사용중인 PC의 성능이 Windows 11 최소 사양을 충족하지 못해 우여곡절 끝에 멀티부트로 Ubuntu를 설치하고, 불가피한 상황에는 Windows 10을 사용하기로 했습니다.
학생 시절 개발자 짬이 어디 안가서 Ubuntu를 설치하자마자 내가 원하는 환경에 맞추어 프로그램 및 라이브러리를 추가로 설치했습니다. 인터넷 브라우저도 기본 제공되는 FireFox 대신 Google Chrome을 설치해 사용하기로 했습니다.
그런데 이러한 과정에서 생각지도 못한 상황이 발생하였습니다. 저는 평소에 Windows에서 Youtube 영상을 보면서 다른 작업을 하고 싶을 때 저는 PIP(Picture in Picture)모드로 동영상을 모니터의 구석에 띄어두고 작업을 했었습니다.

Chrome 우상단의 동영상 제어 버튼 클릭 후 해당 유튜브 동영상의 'PIP 모드 시작' 버튼을 클릭 한 다음

동영상이 별도의 창으로 분리되었을 때 Chrome의 다른 탭을 눌렀더니

놀랍게도 PIP모드로 띄어두었던 동영상이 난데 없이 사라져버렸습니다. 동영상의 사운드는 끊기지 않고 재생되는 것으로 보아 Ubuntu에서의 설정 문제로 보였고, 원인 해결을 위해 GPT에게 질문을 해보았습니다.

결과를 확인해보니 Linux 버전의 Chrome에서는 PIP모드 실행시 동영상 창의 설정이 '항상 위'로 되어 있지 않은 모양입니다.
GPT가 설명한 대로 PIP 모드로 동영상 창을 띄운 다음 Alt + Space 키를 누르니 아래와 같은 메뉴가 나타났습니다.

해당 메뉴에서 '항상 위'를 클릭한 다음 다른 탭을 열어보니

성공적으로 PIP 동영상 창이 사라지지 않고 항상 떠잇는 것을 확인하였습니다.
'공대생의 팁' 카테고리의 다른 글
| [논문 리뷰] 처음 보는 물체도 덥석! 박스 모델링으로 해결하는 로봇의 손동작(Minimum Volume Bounding Box Decompos (0) | 2026.02.01 |
|---|---|
| Ubuntu로 apt 사용시 SSL 인증서 신뢰 문제 발생시 해결방법 (0) | 2025.11.28 |
| 티스토리에서 카카오 로그인시 튀어나오는 팝업 광고 삭제 방법 (0) | 2025.05.20 |
| Huggingface에서 데이터셋 다운로드가 계속 끊길때 해결방법 (0) | 2025.01.14 |
| Flask 라이브러리로 이미지를 업로드하고 볼 수 있는 서버 구축하기 (0) | 2024.10.26 |
설정
트랙백
댓글
글
TensorRT 10버전 이후 변환된 모델을 C++에서 Inference 수행 방법(enqueueV3 함수 사용법)

※본 글을 작성했던 2025년 8월 당시 TensorRT 코드 작성을 GPT 4o에가 요청시 TensorRT 8버전을 기준으로 C++에서 Inference 수행시 'enqueueV2'를 사용하는 것으로만 코드 작성을 해줘서 온갖 고난 끝에 참고자료 페이지의 자료를 찾아내 enqueueV3() 함수 사용 방법을 작성하였습니다. 그런데 GPT5가 2024년 10월 1일까지의 자료를 학습하게 됨으로서 지금은 TensorRT 10 버전 기준으로 enqueueV3 함수를 잘 작성해줍니다.
TensorRT 10 버전이 등장하면서 변환된 모델을 C++에서 Inference 수행시 enqueueV3() 함수를 사용하여야 하며, 기존 8버전에서 사용했던 enqueueV2() 함수를 더이상 사용되지 않게 되었습니다. TensorRT 버전 변경에 따라 코드 변경 사항이 많아져 방법을 찾다가 아래 링크의 참고자료의 내용대로 코드를 작성하니 TensorRT 10 기준으로 변환된 AI모델이 잘 동작하는 것을 확인할 수 있었습니다.
아래의 소스코드는 퍼플렉시티AI의 도움으로 소스코드 설명을 주석으로 작성하였습니다. 아래의 흐름대로 코드를 작성하시면 TensorRT 10버전 이후 enqueueV3() 함수를 작성하는데 큰 어려움은 없을 것입니다.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
|
#include <fstream>
#include <iostream>
#include <memory>
#include <vector>
#include <string>
#include <opencv2/opencv.hpp>
#include <NvInfer.h>
#include <cuda_runtime_api.h>
// CUDA 에러 체크 매크로 및 함수
#define CHECK_CUDA_ERROR(val) check((val), #val, __FILE__, __LINE__)
void check(cudaError_t err, const char* const func, const char* const file, const int line) {
if (err != cudaSuccess) {
std::cerr << "CUDA Runtime Error at: " << file << ":" << line << std::endl;
std::cerr << cudaGetErrorString(err) << " " << func << std::endl;
std::exit(EXIT_FAILURE);
}
}
// TensorRT 로그 출력을 위한 커스텀 Logger 클래스
class CustomLogger : public nvinfer1::ILogger {
void log(nvinfer1::ILogger::Severity severity, const char* msg) noexcept override {
// info 이하 레벨만 출력
if (severity <= nvinfer1::ILogger::Severity::kINFO) {
std::cout << msg << std::endl;
}
}
};
// TensorRT 객체 자동 삭제를 위한 Deleter 구조체
struct InferDeleter {
template <typename T>
void operator()(T* obj) const {
delete obj;
}
};
// Pascal VOC 21 클래스 색상 팔레트 (B,G,R 순서, OpenCV는 BGR)
cv::Vec3b getPascalVOCColor(int class_id) {
static const std::vector<cv::Vec3b> palette = {
{ 0, 0, 0}, // 0: background (black)
{128, 0, 0}, // 1: aeroplane
{ 0,128, 0}, // 2: bicycle
{128,128, 0}, // 3: bird
{ 0, 0,128}, // 4: boat
{128, 0,128}, // 5: bottle
{ 0,128,128}, // 6: bus
{128,128,128}, // 7: car
{ 64, 0, 0}, // 8: cat
{192, 0, 0}, // 9: chair
{ 64,128, 0}, // 10: cow
{192,128, 0}, // 11: diningtable
{ 64, 0,128}, // 12: dog
{192, 0,128}, // 13: horse
{ 64,128,128}, // 14: motorbike
{192,128,128}, // 15: person
{ 0, 64, 0}, // 16: potted plant
{128, 64, 0}, // 17: sheep
{ 0,192, 0}, // 18: sofa
{128,192, 0}, // 19: train
{ 0, 64,128} // 20: tv/monitor
};
if (class_id < 0 || class_id >= palette.size()) return {0,0,0};
return palette[class_id];
}
int main(int argc, char** argv) {
// 1. 입력 이미지 경로 및 엔진 파일 경로 지정
std::string image_path = "input.jpg"; // 입력 이미지 파일명
std::string engine_file_path = "end2end.engine"; // TensorRT 엔진 파일명
// 2. OpenCV로 이미지 읽기 (BGR)
cv::Mat img = cv::imread(image_path, cv::IMREAD_COLOR);
if (img.empty()) {
std::cerr << "이미지를 읽을 수 없습니다: " << image_path << std::endl;
return EXIT_FAILURE;
}
// RGB로 변환 (딥러닝 모델은 보통 RGB 입력)
cv::cvtColor(img, img, cv::COLOR_BGR2RGB);
// 3. TensorRT 엔진 역직렬화 및 실행 컨텍스트 생성
CustomLogger logger{};
std::ifstream engine_file(engine_file_path, std::ios::binary);
if (!engine_file) {
std::cerr << "엔진 파일을 열 수 없습니다: " << engine_file_path << std::endl;
return EXIT_FAILURE;
}
// TensorRT 모델을 메모리에 로드
engine_file.seekg(0, std::ios::end);
size_t engine_file_size = static_cast<size_t>(engine_file.tellg());
engine_file.seekg(0, std::ios::beg);
std::unique_ptr<char[]> engine_data(new char[engine_file_size]);
engine_file.read(engine_data.get(), engine_file_size);
std::unique_ptr<nvinfer1::IRuntime, InferDeleter> runtime{nvinfer1::createInferRuntime(logger)};
std::unique_ptr<nvinfer1::ICudaEngine, InferDeleter> engine{
runtime->deserializeCudaEngine(engine_data.get(), engine_file_size)};
std::unique_ptr<nvinfer1::IExecutionContext, InferDeleter> context{
engine->createExecutionContext()};
// 4. 입력/출력 텐서 이름, shape, dtype 확인
// (엔진에 따라 다를 수 있으니 반드시 확인 필요)
const char* input_tensor_name = engine->getIOTensorName(0); // 입력 텐서 이름
const char* output_tensor_name = engine->getIOTensorName(1); // 출력 텐서 이름
nvinfer1::Dims input_dims = engine->getTensorShape(input_tensor_name); // 예: {1, 3, H, W}
nvinfer1::Dims output_dims = engine->getTensorShape(output_tensor_name); // 예: {1, H, W}
int input_batch = input_dims.d[0];
int input_channels = input_dims.d[1];
int input_height = input_dims.d[2];
int input_width = input_dims.d[3];
int output_batch = output_dims.d[0];
int output_height = output_dims.d[1];
int output_width = output_dims.d[2];
// 5. 입력 이미지 전처리 (리사이즈, 정규화, NCHW 변환)
cv::Mat resized;
cv::resize(img, resized, cv::Size(input_width, input_height));
resized.convertTo(resized, CV_32FC3, 1.0 / 255.0); // 0~1 사이의 값으로 Normalization, AI모델이 학습 수행시 설정하였던 값으로 설정
// NCHW로 변환 (OpenCV는 HWC, TensorRT는 NCHW)
std::vector<float> input_tensor(input_channels * input_height * input_width);
std::vector<cv::Mat> rgb_channels(input_channels);
for (int i = 0; i < input_channels; ++i)
rgb_channels[i] = cv::Mat(input_height, input_width, CV_32FC1, input_tensor.data() + i * input_height * input_width);
cv::split(resized, rgb_channels);
// 6. 입력/출력 버퍼 할당 (CUDA)
void* input_device_buffer = nullptr;
size_t input_bytes = input_tensor.size() * sizeof(float);
CHECK_CUDA_ERROR(cudaMalloc(&input_device_buffer, input_bytes));
void* output_device_buffer = nullptr;
size_t output_bytes = output_height * output_width * sizeof(int64_t); // int64 클래스 ID
CHECK_CUDA_ERROR(cudaMalloc(&output_device_buffer, output_bytes));
// 7. TensorRT 실행 컨텍스트에 입력 버퍼 바인딩
context->setTensorAddress(input_tensor_name, input_device_buffer);
// 8. 실제 출력 텐서 shape와 타입 확인
nvinfer1::Dims output_dims = context->getTensorShape(output_tensor_name); // 실제 shape
size_t output_size = 1;
for (int i = 0; i < output_dims.nbDims; ++i) {
output_size *= output_dims.d[i];
}
nvinfer1::DataType output_dtype = engine->getTensorDataType(output_tensor_name);
// 9. 출력 버퍼 할당 및 추론 실행
void* output_device_buffer = nullptr;
size_t output_bytes = 0;
cudaStream_t stream;
CHECK_CUDA_ERROR(cudaStreamCreate(&stream));
// 10. 출력 타입에 따라 분기 처리
if (output_dtype == nvinfer1::DataType::kINT32) {
output_bytes = output_size * sizeof(int32_t);
CHECK_CUDA_ERROR(cudaMalloc(&output_device_buffer, output_bytes));
context->setTensorAddress(output_tensor_name, output_device_buffer);
// 추론 실행
bool status = context->enqueueV3(stream);
if (!status) {
std::cerr << "TensorRT 추론 실행에 실패했습니다." << std::endl;
return EXIT_FAILURE;
}
CHECK_CUDA_ERROR(cudaStreamSynchronize(stream));
// 결과 복사 및 마스킹
std::vector<int32_t> output_tensor(output_size);
CHECK_CUDA_ERROR(cudaMemcpy(output_tensor.data(), output_device_buffer, output_bytes, cudaMemcpyDeviceToHost));
// 마스크 생성
int mask_height = output_dims.d[output_dims.nbDims - 2];
int mask_width = output_dims.d[output_dims.nbDims - 1];
cv::Mat mask(mask_height, mask_width, CV_8UC3);
for (int y = 0; y < mask_height; ++y) {
for (int x = 0; x < mask_width; ++x) {
int class_id = static_cast<int>(output_tensor[y * mask_width + x]);
mask.at<cv::Vec3b>(y, x) = getPascalVOCColor(class_id);
}
}
cv::Mat mask_resized;
cv::resize(mask, mask_resized, img.size(), 0, 0, cv::INTER_NEAREST);
cv::Mat blended;
cv::addWeighted(img, 0.6, mask_resized, 0.4, 0, blended);
cv::cvtColor(blended, blended, cv::COLOR_RGB2BGR);
cv::imwrite("output_masked_voc.jpg", blended);
std::cout << "INT32 타입 결과를 output_masked_voc.jpg로 저장했습니다." << std::endl;
}
else if (output_dtype == nvinfer1::DataType::kINT64) {
output_bytes = output_size * sizeof(int64_t);
CHECK_CUDA_ERROR(cudaMalloc(&output_device_buffer, output_bytes));
context->setTensorAddress(output_tensor_name, output_device_buffer);
// 추론 실행
bool status = context->enqueueV3(stream);
if (!status) {
std::cerr << "TensorRT 추론 실행에 실패했습니다." << std::endl;
return EXIT_FAILURE;
}
CHECK_CUDA_ERROR(cudaStreamSynchronize(stream));
// 결과 복사 및 마스킹
std::vector<int64_t> output_tensor(output_size);
CHECK_CUDA_ERROR(cudaMemcpy(output_tensor.data(), output_device_buffer, output_bytes, cudaMemcpyDeviceToHost));
int mask_height = output_dims.d[output_dims.nbDims - 2];
int mask_width = output_dims.d[output_dims.nbDims - 1];
cv::Mat mask(mask_height, mask_width, CV_8UC3);
for (int y = 0; y < mask_height; ++y) {
for (int x = 0; x < mask_width; ++x) {
int class_id = static_cast<int>(output_tensor[y * mask_width + x]);
mask.at<cv::Vec3b>(y, x) = getPascalVOCColor(class_id);
}
}
cv::Mat mask_resized;
cv::resize(mask, mask_resized, img.size(), 0, 0, cv::INTER_NEAREST);
cv::Mat blended;
cv::addWeighted(img, 0.6, mask_resized, 0.4, 0, blended);
cv::cvtColor(blended, blended, cv::COLOR_RGB2BGR);
cv::imwrite("output_masked_voc.jpg", blended);
std::cout << "INT64 타입 결과를 output_masked_voc.jpg로 저장했습니다." << std::endl;
}
else if (output_dtype == nvinfer1::DataType::kFLOAT) {
output_bytes = output_size * sizeof(float);
CHECK_CUDA_ERROR(cudaMalloc(&output_device_buffer, output_bytes));
context->setTensorAddress(output_tensor_name, output_device_buffer);
// 추론 실행
bool status = context->enqueueV3(stream);
if (!status) {
std::cerr << "TensorRT 추론 실행에 실패했습니다." << std::endl;
return EXIT_FAILURE;
}
CHECK_CUDA_ERROR(cudaStreamSynchronize(stream));
// 결과 복사 및 마스킹
std::vector<float> output_tensor(output_size);
CHECK_CUDA_ERROR(cudaMemcpy(output_tensor.data(), output_device_buffer, output_bytes, cudaMemcpyDeviceToHost));
int mask_height = output_dims.d[output_dims.nbDims - 2];
int mask_width = output_dims.d[output_dims.nbDims - 1];
cv::Mat mask(mask_height, mask_width, CV_8UC3);
for (int y = 0; y < mask_height; ++y) {
for (int x = 0; x < mask_width; ++x) {
int class_id = static_cast<int>(output_tensor[y * mask_width + x]);
mask.at<cv::Vec3b>(y, x) = getPascalVOCColor(class_id);
}
}
cv::Mat mask_resized;
cv::resize(mask, mask_resized, img.size(), 0, 0, cv::INTER_NEAREST);
cv::Mat blended;
cv::addWeighted(img, 0.6, mask_resized, 0.4, 0, blended);
cv::cvtColor(blended, blended, cv::COLOR_RGB2BGR);
cv::imwrite("output_masked_voc.jpg", blended);
std::cout << "FLOAT 타입 결과를 output_masked_voc.jpg로 저장했습니다." << std::endl;
}
else {
std::cerr << "지원하지 않는 출력 데이터 타입입니다." << std::endl;
return EXIT_FAILURE;
}
// 11. 자원 해제
CHECK_CUDA_ERROR(cudaFree(input_device_buffer));
if (output_device_buffer) CHECK_CUDA_ERROR(cudaFree(output_device_buffer));
CHECK_CUDA_ERROR(cudaStreamDestroy(stream));
return 0;
}
|
cs |
참고자료: https://leimao.github.io/blog/TensorRT-Custom-Plugin-Example/
TensorRT Custom Plugin Example
TensorRT Custom Plugin Implementation and Integration
leimao.github.io
'프로그래밍 팁' 카테고리의 다른 글
| libtorch_cpu.so: undefined symbo: iJIT_NotifyEvent (0) | 2025.07.02 |
|---|---|
| git 사용시 오류 발생 해결 방법 - schannel: next InitializedSecurityContext failed (0) | 2025.03.17 |
| VirtualBox에 Ubuntu 24.04를 설치 후 해상도 확장하는 방법 (0) | 2025.01.02 |
| Ubuntu 24.04에서 apt 저장소를 mirror 사이트를 변경하는 방법 (0) | 2024.12.28 |
| MMCV 라이브러리로 Custom AI모델을 만들어보자!(1) - Backbone 추가하기 (2) | 2024.08.31 |
설정
트랙백
댓글
글
Windows 환경에서 Visual Studio Code로 Libtorch 라이브러리를 사용해 Torchscript 실행 프로그램 빌드 및 실행
Pytorch로 학습한 AI모델을 C++환경에서 구동하는 방법 중 하나인 Torchscript를 사용하기 위해 Libtorch를 다운로드한 후 Torchscript를 불러오는 간단한 예제를 만들어 테스트를 하려 했더나 아래와 같은 에러가 저를 반겼습니다...
Debug Assertion Failed!
File: minkernel\crts\ucrt\src\appcrt\stdio\fopen.cpp
line: 30
Expressing: file_name != nullptr
For information on how your program can cause an assertion failure, see the Visual C++ documentation on asserts.
(Press Retry to debug the application)

위 에러를 해결하기 위해 구글링 및 GPT를 사용해보았으나 마땅한 해답을 찾지 못하였습니다. 저와 같은 에러가 발생하였던 케이스들의 경우들도 오류의 원인 해결에 대한 언급이 없는 것으로 보았을 때 제 환경에서의 문제인 것으로 추정하였습니다.
테스트 수행을 위해 Libtorch 라이브러리 설치 단계부터 차근차근 다시 시도해보았습니다.
1. Pytorch 공식 페이지에서 Libtorch를 설치합니다. Release와 Debug 버전 두 가지 중 하나만 선택하여 다운로드합니다. 2개의 버전을 동시에 사용할 경우 문제가 복잡해질 가능성이 있습니다. 저의 경우 Pytorch 버전과 일치하는 Libtorch를 다운로드하였습니다. 공식 페이지에서는 최신 버전의 Libtorch만 제공되므로 혹시 이전 버전의 Libtorch를 찾고 싶으신 분은 아래의 페이지를 참조해주시기 바랍니다.
Libtorch 이전 버전을 다운로드 하는 방법
Pytorch로 AI모델 프로그래밍을 하다보면 버전 충돌 등으로 인해 과거의 Pytorch 버전을 설치해야 하는 상황에 직면하는 경우가 자주 있다보니 과거의 Pytorch 버전을 설치하곤 합니다. Pytorch 공식 홈
elecs.tistory.com
2. 다운로드한 Libtorch를 압축해제한 후 lib 폴더 경로를 아래와 같이 환경변수 'Path'에 등록합니다.

3. Visual Studio Code를 실행하여 C++ 개발 환경을 설정해줍니다. SHIFT + CTRL + P를 입력하여 명령팔레트에서 C/C++: 구성 편집을 찾아줍니다.

4. 위 과정에서 'c_cpp_properties.json' 파일이 생성됩니다. 아래와 같이 Libtorch에 있는 Library 파일 경로들을 추가해줍니다.
"includePath" [
"${workspaceFolder}/**,
"(Libtorch 설치 경로)/include",
"(Libtorch 설치 경로)/include/torch/csrc/api/include"
]

5. 이번에는 명령팔레트에서 작업:기본 빌드 작업 구성 → C/C++: cl.exe 활성 파일 빌드를 선택합니다.


6. 위 과정에서 'tasks.json' 파일이 생성된 것을 확인할 수 있습니다. 파일 내부에 아래와 같이 Libtorch 라이브러리를 설치해줍니다.
"args": [
....
"${file}",
"/I",
"(Libtorch 설치 경로)/include"
"/I",
"(Libtorch 설치 경로)/include/torch/csrc/api/include",
"/link",
"/LIBPATH:(Libtorch 설치 경로)/lib",
"c10.lib",
"torch.lib",
"torch_cpu.lib",
"torch_cuda.lib"
]
7. 이제 VSCode에 Libtorch 라이브러리 관련 설정이 모두 완료되었습니다. 아래의 예제 소스코드를 작성합니다.
test.cpp
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#include <iostream>
#include <torch/script.h>
#include <torch/cuda.h>
using namespace std;
int main(){
torch::jit::script::Module module;
torch::Tensor tensor = torch::rand({1, 3});
cout << "Random Tensor: " << tensor << end;
cout << torch::cuda::is_available() << endl;
try {
torch::Device device(torch::kCUDA, 0); // GPU 사용
torch::Device device(torch::kCPU); // CPU 사용
string script = "end2end.pt";
module = torch::jit::load(script, device);
} catch (const c10::Error& e) {
cerr << "error loading the module \n";
return -1;
}
cout << "ok" << endl;
}
|
cs |
8. 입력한 소스코드를 'Ctrl + Shift + b" 버튼으로 Build를 수행합니다.
위 예제 소스코드 실행에 성공하셨다면 이제 본격적으로 Torchscript를 개발할 수 있는 환경이 갖추어진 것입니다.
'프로그래밍 팁 > Pytorch' 카테고리의 다른 글
| Libtorch 이전 버전을 다운로드 하는 방법 (0) | 2025.06.02 |
|---|---|
| Pytorch로 학습한 Image AI모델을 Torchscript로 변환 및 실행방법 (0) | 2025.02.20 |
설정
트랙백
댓글
글
libtorch_cpu.so: undefined symbo: iJIT_NotifyEvent
AI모델을 학습하는 과정에서 최신 버전의 Pytorch에서 원활하게 작동되지 않는 케이스가 있어 이전 버전의 Pytorch를 설치후 import 하는 과정에서 아래와 같은 에러가 발생하였습니다.
libtorch_cpu.so: undefined symbo: iJIT_NotifyEvent
이 오류는 주로 PyTorch와 Intel MKL 라이브러리간의 호환성 문제로 발생한다고 합니다. MKL(Intel Math Kernel Library)은 인텔에서 제공하는 고성능 수치 연산 라이브러리로서 최신 MKL 버전에서 일부 심볼이 제거되어 이러한 문제가 발생할 수 있다고 합니다.
해당 오류는 아래의 방법과 같이 MKL의 버전을 낮춤으로서 해결할 수 있었습니다.
conda install mkl==2024.0
또는
pip install mkl==2024.0
'프로그래밍 팁' 카테고리의 다른 글
| TensorRT 10버전 이후 변환된 모델을 C++에서 Inference 수행 방법(enqueueV3 함수 사용법) (0) | 2025.09.05 |
|---|---|
| git 사용시 오류 발생 해결 방법 - schannel: next InitializedSecurityContext failed (0) | 2025.03.17 |
| VirtualBox에 Ubuntu 24.04를 설치 후 해상도 확장하는 방법 (0) | 2025.01.02 |
| Ubuntu 24.04에서 apt 저장소를 mirror 사이트를 변경하는 방법 (0) | 2024.12.28 |
| MMCV 라이브러리로 Custom AI모델을 만들어보자!(1) - Backbone 추가하기 (2) | 2024.08.31 |
설정
트랙백
댓글
글
Libtorch 이전 버전을 다운로드 하는 방법
Pytorch로 AI모델 프로그래밍을 하다보면 버전 충돌 등으로 인해 과거의 Pytorch 버전을 설치해야 하는 상황에 직면하는 경우가 자주 있다보니 과거의 Pytorch 버전을 설치하곤 합니다. Pytorch 공식 홈페이지에서는 Python 에서 동작하는 이전 버전의 Pytorch를 설치하는 방법을 자세히 설명하고 있습니다.
https://pytorch.org/get-started/previous-versions/
Previous PyTorch Versions
Access and install previous PyTorch versions, including binaries and instructions for all platforms.
pytorch.org
그러나 해당 링크를 통해서는 C++ 환경에서 Pytorch로 학습된 AI모델을 구동할 수 있게 해주는 Libtorch의 이전 버전에 대한 설치 방법을 설명하지 않고 있습니다. 최신 버전의 Libtorch의 경우 다운로드 링크를 제공하고 있으나 이전 버전의 링크는 해당 페이지에서는 확인할 수 없습니다.
다행히도 Pytorch 웹페이지를 오픈소스로 공개한 github 페이지에서 이전 버전의 Libtorch 링크를 찾을 수 있습니다.
https://github.com/pytorch/pytorch.github.io/blob/site/published_versions.json
pytorch.github.io/published_versions.json at site · pytorch/pytorch.github.io
The website for PyTorch. Contribute to pytorch/pytorch.github.io development by creating an account on GitHub.
github.com
위 페이지에서 json 양식으로 작성된 파일 내에서 자신이 원하는 Libtorch의 버전을 찾으실 수 있습니다.

'프로그래밍 팁 > Pytorch' 카테고리의 다른 글
| Windows 환경에서 Visual Studio Code로 Libtorch 라이브러리를 사용해 Torchscript 실행 프로그램 빌드 및 실행 (0) | 2025.08.01 |
|---|---|
| Pytorch로 학습한 Image AI모델을 Torchscript로 변환 및 실행방법 (0) | 2025.02.20 |
설정
트랙백
댓글
글
티스토리에서 카카오 로그인시 튀어나오는 팝업 광고 삭제 방법
평소 PC를 사용할때 의심스러운 프로그램은 절대 설치하지 않는 것을 원칙으로 해왔으며, 프로그램 설치 과정에서 무의식적으로 광고 프로그램 설치 버튼을 누르지 않으려 단계별로 꼼꼼히 확인하며 컴퓨터를 관리해왔던 저의 습관 덕분에 지난 7년동안 단 한번도 악성코드 없는 청정한 환경의 PC를 유지해왔습니다.
그러나 그토록 악성코드를 경계하면서 살아오던 저였습니다만 허무하게도 안타까운 상황이 벌어지고 말았습니다. 언제나 그랬듯이 평소처럼 티스토리에 오랜만에 포스팅을 작성하고자 티스토리에 접속한 다음

'카카오계정으로 로그인' 버튼을 클릭했더니

난생 처음보는 팝업창이 뙇! 하고 로그인창을 가려버립니다. '온라인쇼핑/금융사기 예방방법'이라는 거창한 제목을 적어두고는 'AD'라고 적혀있는 화면에서부터 굉장히 불순한 냄새가 풀풀 풍깁니다..
처음에는 단순한 팝업 예외처리 문제로 해결할 수 있으리라 판단되어 AdBlock을 Chrome 확장프로그램으로 설치하였습니다만 같은 현상이 계속 나타는 것이었습니다. 심지어 저와 같은 현상이 발생하는 다른 블로거 분들의 해결책을 써봐도 도통 해결이 되지 않고 있던 찰나...
우연히 발견한 이 분께서 작성하신 포스팅의 내용대로 제 의도와는 하등 관계없이 컴퓨터에 악성코드가 강제로 설치되어 버렸고 이로 인해 티스토리 로그인을 시도할 때 마다 악질같은 광고창이 계속 뜨는 현상이 발생하는 것임을 알게 되었습니다.
(극강 무료 프로그램) 로그인 시, 팝업광고 노출 악성코드 멀웨어 제거 방법
어느 날, 티스토리 블로그를 하기 위해 [로그인]을 하는 순간, 갑자기 [팝업 광고]가 똭! 하니 등장했습니다. 허걱! ''이게 뭐지?' "뭔가 프로그램(앱)을 깔았나?" "별로 설치한 것도 없는데..."
reportandmore.tistory.com
위 포스팅에서 소개한 악성코드 제거 도구인 'Malware Zero'를 아래의 공식 웹페이지를 통해 바로 다운로드하였습니다.
Malware Zero - 무료 악성코드 제거 도구
악성코드 및 애드웨어 등 각종 유해 프로그램에 의한 고통에서 해방되기 위해 설치 없이 사용 가능한 무료 악성코드 제거 도구
malzero.xyz
Malware Zero를 다운로드한 다음 압축을 해제하면 'malzero'라는 이름의 폴더를 연 다음 'start'를 관리자권한으로 실행하였습니다.

아래와 같은 창들에서 '예'를 클릭하고


아래의 화면과 같이 Malware Zero가 검사를 수행합니다. 저의 경우 약 20분 정도 수행되었습니다. 한동안 백신 검사를 수행하지 않았어서 그런지 마치 내 하드디스크의 묵은 때를 벆벆 긁어내듯이 악성코드 제거 프로그램이 악성코드를 찾아내는 듯한 느낌이었습니다.

아래와 같은 화면이 나오면 검사가 완료된 것입니다.

창을 닫자마자 메모장이 열리며 검사 결과를 알려줍니다.(생각보다 너무나도 많은 악성코드들이 발견되어 놀랐습니다. 나름 주의를 기울이며 PC를 써왔음에도 이렇게 속수무책으로 당하고 있었을 줄은 생각도 못했습니다.)

검사가 끝난 후 컴퓨터를 껏다 킨 다음 티스토리 로그인을 시도해보니 다행히도 지금까지 지금껏 저를 괴롭히던 악성 팝업 광고창이 나타나지 않고 있습니다. 이 프로그램으로 원인을 찾아내고 악성코드를 말끔히 제거하니 7년 묵은 제 PC가 새 PC마냥 산뜻해진 듯한 느낌입니다.
혹시 이 글을 보고 계신 여러분들 중에도 저와 같은 현상이 반복되시는 분이 계시다면 지금 바로 Malware Zero를 다운로드하여 PC 내에 악성코드가 있는지 확인해보시기 바랍니다!
'공대생의 팁' 카테고리의 다른 글
| Ubuntu로 apt 사용시 SSL 인증서 신뢰 문제 발생시 해결방법 (0) | 2025.11.28 |
|---|---|
| Ubuntu에서 Youtube 동영상 PIP모드에서 다른 창에 의해 화면이 가려질 때 해결방법 (0) | 2025.10.28 |
| Huggingface에서 데이터셋 다운로드가 계속 끊길때 해결방법 (0) | 2025.01.14 |
| Flask 라이브러리로 이미지를 업로드하고 볼 수 있는 서버 구축하기 (0) | 2024.10.26 |
| Windows Powershell에서 python 실행시 환경변수 설정 방법 (0) | 2024.05.28 |
설정
트랙백
댓글
글
포항 영일만 바닷가를 옆에 두고 - 영일만항선 영일만항역(2025.04.01)
코로나 시기에 서핑이 유행하던 즈음 영일만항 인근에 있는 용한리 해수욕장에서 서핑을 도전해본 적이 있었습니다. 가던 길에 6차선 도로를 철길건널목으로 가르질러 컨테이너가 가득한 항만으로 이어지던 영일만항선 철길이 보았었습니다.
영일만항선은 10년전 포항역이 시내에서 외곽으로 이설되는 과정에서 신축 역사에서 영덕 방면 연장 구간에서 분기하여 영일만항에서 화물을 취급하기 위해 2019년에 신설된 노선으로 여객 취급이 없는 구간이다 보니 이 곳을 찾아오는 분들은 해수욕장을 방문하는 분들이 거의 대부분일겁니다.
지난 여름 서핑을 즐기며 보던 바다의 모습을 다시 한 번 보는 김에 영일만항역을 찾아가 보았습니다.

포항 시내 외곽에 위치한 영일만대로를 쭈욱 달려오면 영일만항로와 접하는 삼거리가 나오는데 바로 그 앞에 보이는 건물이 영일만항역입니다.

3년전에 왔을때엔 없던 역명판을 붙여놓았네요. 항만 내 역의 위치를 확실히 알 수 있게 되었습니다.

영일만대로 북쪽으로 가다보면 6차선을 가로지르는 영일만신항건널목이 나타납니다.

철길이 대로를 비스듬히 지나가다보니 건널목 길이가 꽤 깁니다.

항만으로 들어가는 길은 열차가 통과하지 않는 시간에는 굳건히 닫혀있습니다.

용한리 해수욕장 방향을 바라본 모습

항만 내부 방향으로 찍은 모습입니다.

건널목의 규모가 크지만 열차 통행이 빈번하지는 않아 큰 사고가 날 것 같지는 않을거같습니다.

시내와는 동떨어진 곳이어서 차량도 많이 다니지는 않다보니 건널목을 설치해도 큰 문제는 없어보입니다.

항만에서 곧 열차가 나올 시간이 다가오자 건널목 신호기가 요란한 소리를 내기 시작합니다.

워낙에 넓은 대로에 있는 건널목이어서 차단봉이 휠 정도로 길다랗습니다.

컨테이너 화물이 연결된 기관차가 항만을 빠져나오기 시작합니다.

건널목관리원이 주변 차량들을 통제하고 있습니다.







열차가 통과하는 모습을 보고 가려고 했는데 건널목관리원분께서 저에게 걸어오셔서 뭘 찍고있는지 물어보셨습니다. 열차가 나오는 시간을 어떻게 알고 찾아왔는지 저를 의심하는 질문에 대해 기차를 좋아해서 사진을 찍고 싶어 찾아왔다는 대답을 해드리니 상황을 어느정도 이해하시고 대기실로 돌아가셨습니다.

용한리 해수욕장에서 영일만항을 바라보며 하루를 마칩니다..
'좌충우돌 여행기 > 국내여행' 카테고리의 다른 글
| 2024년의 끝을 앞두고 사라지다 - 중앙선 북영천역(+화본역) (0) | 2024.12.16 |
|---|---|
| 중앙선 이설전 마지막 풍경들 - 의성역~우보역 구간(2024.12.01) (0) | 2024.12.06 |
| 중앙선 이설전 마지막 풍경들 - 북영천역~갑현역 구간(2024.11.22) (0) | 2024.11.23 |
| 중앙선에 남은 마지막 아담한 간이역 - 화본역(2024.07.27) (0) | 2024.09.30 |
| 뒤바뀐 운명 - 중앙선 건천역과 아화역(2024.07.27) (0) | 2024.07.28 |
설정
트랙백
댓글
글
git 사용시 오류 발생 해결 방법 - schannel: next InitializedSecurityContext failed
사내에서 git으로 라이브러리를 다음과 같이 다운로드를 시도하였습니다.
$ git clone https://github.com/open-mmlab/mmcv.git
그런데, 다음과 같은 오류가 발생하였습니다.
fatal: unable to access 'https://github.com/open-mmlab/mmcv.git/': schannel: next InitializeSecurityContext failed: CRYPT_E_REVOCATION_OFFLINE (0x80092013)
위 에러는 사내 보안에 의해 SSL 관련 기능들이 차단되어 발생하는 오류였습니다. 아래와 같이 git에서 ssl체크 기능을 사용하지 않으면 git을 정상적으로 사용할 수 있습니다.
$ git -c http.sslVerify=false clone http://github.com/open-mmlab/mmcv.git/
'프로그래밍 팁' 카테고리의 다른 글
| TensorRT 10버전 이후 변환된 모델을 C++에서 Inference 수행 방법(enqueueV3 함수 사용법) (0) | 2025.09.05 |
|---|---|
| libtorch_cpu.so: undefined symbo: iJIT_NotifyEvent (0) | 2025.07.02 |
| VirtualBox에 Ubuntu 24.04를 설치 후 해상도 확장하는 방법 (0) | 2025.01.02 |
| Ubuntu 24.04에서 apt 저장소를 mirror 사이트를 변경하는 방법 (0) | 2024.12.28 |
| MMCV 라이브러리로 Custom AI모델을 만들어보자!(1) - Backbone 추가하기 (2) | 2024.08.31 |