import serial # pip install pyserial
import binascii # pip install binascii
try:
# Change Serial('COM Port to your environment')
ser = serial.Serial('COM5', 115200)
except serial.SerialException as e:
print(f"Error opening serial port: {e}")
exit(1)
while True:
if ser.readable():
s = ser.read(1) # Reading 1 byte at a time
hex_string = binascii.hexlify(s).decode('utf-8')
print(hex_string, end=" ")
if hex_string == 'fa':
print("\n")
Python 코드의 결과로 위 사진과 같은 hex 배열을 얻게 된다.
0x55 0xAA 는 헤더고, 0xFA 는 end sign 이다. 데이터시트를 보면 예시도 있으므로 참고하면 되겠다.
예시를 한 번 보자.
현재 아두이노 코드는 command 를 measuring distance 하나만 보내고 있다.
detect 되는 거리는 3cm ~ 2m 까지이기 때문에 최대 2000 mm 까지 감지 가능하다.
참고) 2000 은 0x07D0
참고) 앞에 나왔던 55 AA 81 03 에서 03 은 다음과 같음
03은 뒤에 나오는 parameter 길이
그럼 길이를 한번 다시 재본다.
코드는 다음과 같다.
import serial # pip install pyserial
import binascii # pip install binascii
idx = 0
distance = 0
try:
# Change Serial('COM Port to your environment')
ser = serial.Serial('COM5', 115200)
except serial.SerialException as e:
print(f"Error opening serial port: {e}")
exit(1)
while True:
if ser.readable():
s = ser.read(1) # Reading 1 byte at a time
hex_string = binascii.hexlify(s).decode('utf-8')
if idx == 4 or idx == 5:
# Append incoming hex values and convert to decimal
if idx == 4:
distance = int(hex_string, 16) << 8 # Shift left by 8 bits for the high byte
elif idx == 5:
distance += int(hex_string, 16) # Add the low byte value
print(f"Distance: {distance} mm") # Print the distance
if idx == 6 and hex_string != '00':
print("WARNING: Out of range!")
# Index increment
idx += 1
if hex_string == 'fa':
# Reset packet on end signal
idx = 0
distance = 0
print("\n")
정상적으로 출력되는 것을 볼 수 있다.
time.sleep() 을 사용해서 딜레이도 줘 봤는데, UART 통신이 뭔가 이상해져서 다시 뺐다.
from PIL import Image
import torchvision.transforms as transforms
import torch
image_path = "img.png"
image = Image.open(image_path)
transform = transforms.Compose([
transforms.Resize((28, 28)),
transforms.ToTensor()
])
image_tensor = transform(image)
image_tensor = image_tensor.unsqueeze(0)
tensor_values = image_tensor.numpy()
with open("tensor_values.txt", "w") as f:
for layer in tensor_values:
for row in layer:
for value in row:
f.write(f"{value} ")
f.write("\n")
f.write("\n")
tensor_value.txt
텍스트 파일을 보면 알 수 있는 점이 있다.
다시 그림을 한 번 보자.
보면 오른쪽으로 1픽셀 정도 치우쳐져 있는 그림이다.
값을 한 번 보자.
0.33 .. 값은 첫 번째를 1번이라고 했을 때 14번부터 16번의 값을 가진다!
28x28 의 정 중앙이 14 라는 점을 보았을 때, 딱 1픽셀 밀려 있는 것을 확인 가능하다.
이번에는
0.33 ... 값이 가득한 부분을 한 번 본다.
위에서 부터 1번 row 라고 했을 때 7번에 위치한다.
잘 보면 첫 번째만 값이 이상한데, 이는 의도된 그림이다. 그림을 다시 보면 가장 처음 픽셀만 살짝 연한 것을 볼 수 있다.
따라서, 이 정보들을 보면, 텐서는
저 방향으로 하나의 row 를 끝날 때까지 읽고, 끝나면 다음 row를 출력한다고 보면 되겠다.
그리고 총 형태를 보면,
이다. 우리가 지금까지 봤었던 것은 한 차원의 값이다. 아마 RGB 중 R 값을 본 것 같다.
이는 B의 0.33 ... 값을 보면 더 잘 알 수 있다.
이쪽 부분만 0.58431375 로 값이 같은 것을 알 수 있다.
처음에 값 지정할 때 #555595 로 설정했기 때문에 혼자만 다르게 나오는 것을 볼 수 있다.
커널이 있으면 위 사진처럼 계산도 가능하겠다.
이제 다시 넘파이 배열를 이미지로 변환해 볼 차례이다.
하나 예시를 들어보면, #999999의 RGB 값은 (153, 153, 153) 이다.
153 을 RGB 범위인 255로 나누게 되면 0.6 이라는 값이 나오게 된다.
#555595 는 어떨까? (85, 85, 149) 의 값을 가진다.
85를 RGB 범위인 255로 나누게 되면 0.33333... 의 값이 나온다.
컴퓨터에서는 32비트 범위에서 잘리게 되므로 약간의 소수점 변동이 생길 수 있다.
텐서의 경우 0.33333334 의 값을 가지게 되었다.
149를 255로 나눠보면?
0.5843137254 ... 값이 나온다. 이도 소수점 7번째 자리까지 동일한 값이 나오는 것을 확인 가능하다.
다르게 생각해 보면 R 채널에서는 회색 범위는 153의 값을 가지고, 보라색 범위는 85의 값을 가지는 텐서들로 이루어져 있다.
G 채널에서도 같다.
B 채널에서만 회색 범위가 153이라는 값을 가지고, 보라색 범위가 149의 값을 가지게 된다. 그래서 값 차이가 크게 나지 않는다.
아무튼 다시 이미지로 변경을 한다.
import torchvision.transforms as transforms
import torch
from PIL import Image
# Load the image
image_path = "./img.png"
image = Image.open(image_path)
# Define the transformation
transform = transforms.Compose([
transforms.ToTensor()
])
# Convert the image to a tensor
image_tensor = transform(image)
print(image_tensor.shape)
tf = transforms.ToPILImage()(image_tensor).show()
변형한 것이 없기 때문에 깔끔하게 다시 나온다.
이건 기존에 했던 이미지 - > 바이트 배열 -> 텐서 -> 넘파이 배열 -> 텐서 -> 이미지 변환이다.
from PIL import Image
import torchvision.transforms as transforms
import torch
import numpy as np
# 이미지 불러오기
image_path = "./img.png"
image = Image.open(image_path)
# 이미지 전처리
transform = transforms.Compose([
transforms.Resize((28, 28)), # 모델의 입력 크기로 리사이즈
transforms.ToTensor() # 텐서로 변환
])
image_tensor = transform(image) # 텐서 변환
image_tensor = image_tensor.unsqueeze(0) # 배치 차원 추가
# 텐서를 바이트 값으로 변환하여 바이트 파일로 저장
tensor_bytes = image_tensor.numpy().tobytes() # 텐서를 numpy 배열로 변환 후 바이트로 변환
# 바이트 파일 저장
with open("D:/tensor_values.bytes", "wb") as f:
f.write(tensor_bytes)
# 바이트 파일을 읽어 텐서로 변환
with open("D:/tensor_values.bytes", "rb") as f:
tensor_bytes = f.read()
# 바이트 데이터를 numpy 배열로 변환
tensor_array = np.frombuffer(tensor_bytes, dtype=np.float32)
tensor_array = tensor_array.reshape((1, 3, 28, 28)) # 원래 텐서의 형태로 변환
# numpy 배열을 텐서로 변환
reconstructed_tensor = torch.tensor(tensor_array)
# 텐서를 이미지로 변환
reconstructed_image = transforms.ToPILImage()(reconstructed_tensor.squeeze(0))
# 이미지 저장
reconstructed_image.save("D:/reconstructed_image.jpg")
import torch
from ultralytics import YOLO
# ------------ 모델 경로 및 파일 수정 시간은 수정하기 --------------
model_path = '../best.pt'
model_generated_time = " 24-06-04, 20:02"
# --------------------------------------------------------------
model = YOLO(model_path)
# 모델의 가중치 확인
model_weights = model.model.state_dict()
torch.set_printoptions(threshold=torch.inf)
idx = 0
while idx < len(model_weights):
name = list(model_weights.keys())[idx]
param = model_weights[name]
if "model." in name:
output_file = f"{name}.txt"
with open(output_file, "w") as f:
f.write("Weights Information:\n")
f.write("# weights ver.2\n\n")
f.write(f"Model Path: {model_path}\n")
f.write(f"Model Generated Time: {model_generated_time}\n\n")
f.write(f"Layer: {name} | Size: {param.size()}\n")
f.write(str(param) + "\n")
idx += 1
다음은 레이어 정보만 가져오는 코드임.
# 레이어 정보만 가져오기
import torch
from ultralytics import YOLO
# 모델 경로 및 파일 수정 시간 설정
model_path = '../best.pt'
model_generated_time = "24-06-04, 20:02"
# YOLO 모델 로드
model = YOLO(model_path)
# 모델의 가중치 확인
model_weights = model.model.state_dict()
# 레이어 정보를 저장할 파일 생성
with open("layers.txt", "w") as f:
f.write("Layer Information:\n")
f.write(f"Model Path: {model_path}\n")
f.write(f"Model Generated Time: {model_generated_time}\n\n")
# 각 레이어 정보를 파일에 기록
with open("layers.txt", "a") as f:
for idx, (name, param) in enumerate(model_weights.items()):
f.write(f"Layer {idx}:\n")
f.write(f"Name: {name}\n")
f.write(f"Size: {param.size()}\n")
from ultralytics import YOLO
# Load a model
model = YOLO("best.pt") # pretrained YOLOv8n model
# Run batched inference on a list of images
results = model(["peaches1.jpg", "peaches2.jpg", "peaches3.jpg", "plum1.jpg", "plum2.jpg"]) # return a list of Results objects
# Process results list
for result in results:
boxes = result.boxes # Boxes object for bounding box outputs
masks = result.masks # Masks object for segmentation masks outputs
keypoints = result.keypoints # Keypoints object for pose outputs
probs = result.probs # Probs object for classification outputs
obb = result.obb # Oriented boxes object for OBB outputs
result.show() # display to screen
result.save(filename="result.jpg") # save to disk
우리가 train 시킨 사과가 없으므로, no detection 이 뜨는 것이 당연하다.
다른 사과 이미지를 한 번 넣어본다.
train 시킨 사과 이미지와 다르면 된다.
학습 데이터가 적어서? detect 되지 않는 문제가 발생한다.
val 데이터를 한 번 넣어본다.
* val 데이터, train 데이터도 제대로 출력되지 않는다(?)
* yolov8n 모델로 돌리면 제대로 나온다.
* 데이터 학습이 제대로 안 되었다는 소리
아무튼 yolov8n 모델로 돌려 보았다.
yolov8n.pt
test 데이터는 더 있는데, 학습되지 않은 자두와 복숭아에 대해서 사과와 구분을 잘 못하는 모습을 보였다.
그래서, 다른 모델을 적용시켜 보기로 했다.
small, medium, large 까지만 사용해 보기로 했다.
yolov8s.pt
small 도 이상하다.
coco dataset 에 복숭아와 자두가 없는게 문제가 큰 것 같다.
yolov8m.pt
yolov8l.pt
train 시키지 않은 항목에 대해서 이미 있는것을 바탕으로 추측하고, 사과와 비슷하게 생겼기 때문에 사과로 인지하는 것 같다. 해당 사진은 '자두' 이다.
커스텀 데이터셋을 다시 train 시킬 필요가 있겠다.
epoch 를 60으로 늘렸다. train 데이터도 제대로 검출이 안 되기 때문.
아니면 항목이 하나밖에 없어서 그럴 수도 있다.
last.pt (epochs=60)
best.pt (epochs=60)
last 와 best 가 동일한 결과를 보였다.
이제 사과 비슷한 모양은 비슷하게 검출되는 것을 확인 가능하다. (best.pt 사용했다.)
Full code 도 첨부하도록 하겠다.
필요한 대로 수정하면서 사용하도록 한다.
# --------------------------------------------------
# from ultralytics import YOLO
# model = YOLO('yolov8n.pt')
# model.train(data="C:/Users/admin/Desktop/github/Apple Finder/data.yaml", epochs=60)
# --------------------------------------------------
# from ultralytics import YOLO
# import torch
# model = torch.load("./best.pt")
# print(model)
#----------------------------------------------------
### image predict
from ultralytics import YOLO
# Load a model
model = YOLO("best.pt") # pretrained YOLOv8n model
# Run batched inference on a list of images
# results = model(["app.jpg"]) # return a list of Results objects
results = model(["apple1.jpg",
"apple2.jpg",
"apple3.jpg",
"peaches1.jpg",
"peaches2.jpg",
"peaches3.jpg",
"plum1.jpg"])
# Process results list
for result in results:
boxes = result.boxes # Boxes object for bounding box outputs
masks = result.masks # Masks object for segmentation masks outputs
keypoints = result.keypoints # Keypoints object for pose outputs
probs = result.probs # Probs object for classification outputs
obb = result.obb # Oriented boxes object for OBB outputs
result.show() # display to screen
result.save(filename="result.jpg") # save to disk
#----------------------------------------------------------