pd.set_option(‘display.max_columns’, None)
pd.set_option(‘display.width’, 200) # adjust number as needed

pd.set_option(‘display.max_columns’, None)
pd.set_option(‘display.width’, 200) # adjust number as needed

roslaunch halc0311_simulation turtlebot3_gazebo_halc.launch
rosrun halc0311_simulation turtlebot_move_spawn_write.py (this program is somehow so slow)

Thinking a better way to generate the waypoints…..


#1 run gazebo of simulation map
roslaunch halc0311_simulation turtlebot3_gazebo_halc.launch
#2 run amcl navigation (rviz) reading a scan map
roslaunch turtlebot3_navigation turtlebot3_navigation.launch map_file:=$HOME/catkin_ws/src/halc0311_simulation/map/halc0311_c.yaml
# for keyboard control
roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch
#3 save current amcl pose (waypoint) to a file and mark a waypoint on gazebo
rosrun halc0311_simulation recorddraw_goal2digit_onefile.py
#4 read the waypoint file and let the robot move along the waypoint
rosrun halc0311_simulation megarover_sequence_goals.py goal_sequence_20250316_161024.yaml
# cancel navigation goal
rostopic pub /move_base/cancel actionlib_msgs/GoalID -- {}
run keyboard or mouse
rosrun teleop_twist_keyboard teleop_twist_keyboard.py // not work
roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch //ok
roslaunch megarover3_ros mousectrl.launch




rosmsg show data_transmitter/WifiSignal
https://qiita.com/BEIKE/items/825e62bbd8d92b6d347e
git clone https://github.com/shilohc/map2gazebo.git
cd ~/catkin_ws && catkin build # or catkin_make
source ~/catkin_ws/devel/setup.bashroslaunch map2gazebo map2gazebo.launch params_file:=$(rospack find map2gazebo)/config/defaults.yaml
rosrun map_server map_server map.yaml
zotac-d05@d05:~/catkin_ws/src/halc_simulation/map$ rosrun map_server map_server halc0311_a.yaml
2. Several errors
[ERROR] [1741507226.788502]: bad callback: <bound method MapConverter.map_callback of <__main__.MapConverter object at 0x7fd8238e8f40>>
Traceback (most recent call last):
File "/opt/ros/noetic/lib/python3/dist-packages/rospy/topics.py", line 750, in _invoke_callback
cb(msg)
File "/home/zotac-d05/catkin_ws/src/map2gazebo/src/map2gazebo.py", line 30, in map_callback
contours = self.get_occupied_regions(map_array)
File "/home/zotac-d05/catkin_ws/src/map2gazebo/src/map2gazebo.py", line 72, in get_occupied_regions
image, contours, hierarchy = cv2.findContours(
ValueError: not enough values to unpack (expected 3, got 2)
ValueError: not enough values to unpack (expected 3, got 2)
contours, hierarchy = cv2.findContours(thresh_map, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)AttributeError: ‘Trimesh’ object has no attribute ‘remove_duplicate_faces’
#mesh.remove_duplicate_faces()
mask = mesh.unique_faces()
mesh.update_faces(mask)process[map2gazebo-1]: started with pid [29285]
[INFO] [1766289078.421279]: map2gazebo running
[INFO] [1766289078.432847]: Received map
[ERROR] [1766289080.632500]: bad callback: <bound method MapConverter.map_callback of <__main__.MapConverter object at 0x7f5e2d288100>>
Traceback (most recent call last):
File "/opt/ros/noetic/lib/python3/dist-packages/rospy/topics.py", line 750, in _invoke_callback
cb(msg)
File "/home/zotac-d06/catkin_ws/src/map2gazebo/src/map2gazebo.py", line 43, in map_callback
mesh.export(f, "stl")
File "/home/zotac-d06/.local/lib/python3.8/site-packages/trimesh/base.py", line 2931, in export
return export_mesh(mesh=self, file_obj=file_obj, file_type=file_type, **kwargs)
File "/home/zotac-d06/.local/lib/python3.8/site-packages/trimesh/exchange/export.py", line 101, in export_mesh
result = util.write_encoded(file_obj, export)
File "/home/zotac-d06/.local/lib/python3.8/site-packages/trimesh/util.py", line 2171, in write_encoded
file_obj.write(stuff.decode(encoding))
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x89 in position 81: invalid start byte
Change open function variable from “w” to “wb”
if mesh_type == "stl":
with open(export_dir + "/map.stl", 'wb') as f:
mesh.export(f, "stl")
rospy.loginfo("Exported STL. You can shut down this node now")
elif mesh_type == "dae":
with open(export_dir + "/map.dae", 'wb') as f:
f.write(trimesh.exchange.dae.export_collada(mesh))
3. You can select output between stl or dae

4. The export directory was set to $(find map2gazebo)/models/map/meshes” if there is no this folder, it will say the error…



Then, File -> Save World As halc.world
hence you will get the current camera pose.
copy the models folder to the package where you copy .world to
<launch>
<env name="GAZEBO_MODEL_PATH" value="$(find map2gazebo)/models:$(optenv GAZEBO_MODEL_PATH)" />
<arg name="debug" default="false"/>
<arg name="gui" default="true"/>
<arg name="headless" default="false"/>
<!-- Start Gazebo with a blank world -->
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="debug" value="$(arg debug)" />
<arg name="gui" value="$(arg gui)" />
<arg name="paused" value="false"/>
<arg name="use_sim_time" value="true"/>
<arg name="headless" value="$(arg headless)"/>
<arg name="world_name" value="$(find map2gazebo)/worlds/map.sdf"/>
</include>
</launch><?xml version="1.0" ?>
<sdf version="1.4">
<model name="map">
<link name="link">
<inertial>
<mass>15</mass>
<inertia>
<ixx>0.0</ixx>
<ixy>0.0</ixy>
<ixz>0.0</ixz>
<iyy>0.0</iyy>
<iyz>0.0</iyz>
<izz>0.0</izz>
</inertia>
</inertial>
<collision name="collision">
<pose>0 0 0 0 0 0</pose>
<geometry>
<mesh>
<uri>model://map/meshes/map.stl</uri>
</mesh>
</geometry>
</collision>
<visual name="visual">
<pose>0 0 0 0 0 0</pose>
<geometry>
<mesh>
<uri>model://map/meshes/map.stl</uri>
</mesh>
</geometry>
</visual>
</link>
<static>1</static>
</model>
</sdf>zotac-d05@d05:~/catkin_ws/src$ catkin_create_pkg halc_simulation Created file halc_simulation/package.xml Created file halc_simulation/CMakeLists.txt Successfully created files in /home/zotac-d05/catkin_ws/src/halc_simulation. Please adjust the values in package.xml. zotac-d05@d05:~/catkin_ws/src$ cd halc_simulation zotac-d05@d05:~/catkin_ws/src/halc_simulation$ mkdir -p worlds launch

zotac-d05@d05:~/catkin_ws$ catkin build

Creating a world with turtlebot (this method load map.sdf, unable to adjust the camera pose, just save the world via gazebo is fine!)

<launch>
<arg name="model" default="$(env TURTLEBOT3_MODEL)" doc="model type [burger, waffle, waffle_pi]"/>
<arg name="x_pos" default="0.0"/>
<arg name="y_pos" default="0.0"/>
<arg name="z_pos" default="0.0"/>
<arg name="yaw" default="0.0"/>
<env name="GAZEBO_MODEL_PATH" value="$(find halc_simulation)/models:$(optenv GAZEBO_MODEL_PATH)" />
<!-- Start Gazebo with a blank world -->
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="world_name" value="$(find halc_simulation)/worlds/map.sdf"/>
<arg name="paused" value="false"/>
<arg name="use_sim_time" value="true"/>
<arg name="gui" value="true"/>
<arg name="headless" value="false"/>
<arg name="debug" value="false"/>
</include>
<param name="robot_description" command="$(find xacro)/xacro --inorder $(find turtlebot3_description)/urdf/turtlebot3_$(arg model).urdf.xacro" />
<node pkg="gazebo_ros" type="spawn_model" name="spawn_urdf" args="-urdf -model turtlebot3_$(arg model) -x $(arg x_pos) -y $(arg y_pos) -z $(arg z_pos) -param robot_description" />
</launch>
Use this kind of launch file is better!
<launch>
<arg name="model" default="$(env TURTLEBOT3_MODEL)" doc="model type [burger, waffle, waffle_pi]"/>
<arg name="x_pos" default="0.0"/>
<arg name="y_pos" default="0.0"/>
<arg name="z_pos" default="0.0"/>
<arg name="yaw" default="0.0"/>
<env name="GAZEBO_MODEL_PATH" value="$(find halc_simulation)/models:$(optenv GAZEBO_MODEL_PATH)" />
<!-- Start Gazebo with a blank world -->
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="world_name" value="$(find halc_simulation)/worlds/halc.world"/>
<arg name="paused" value="false"/>
<arg name="use_sim_time" value="true"/>
<arg name="gui" value="true"/>
<arg name="headless" value="false"/>
<arg name="debug" value="false"/>
</include>
<param name="robot_description" command="$(find xacro)/xacro --inorder $(find turtlebot3_description)/urdf/turtlebot3_$(arg model).urdf.xacro" />
<node pkg="gazebo_ros" type="spawn_model" name="spawn_urdf" args="-urdf -model turtlebot3_$(arg model) -x $(arg x_pos) -y $(arg y_pos) -z $(arg z_pos) -param robot_description" />
</launch>roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch
roslaunch halc_simulation turtlebot3_gazebo_halc.launch
roslaunch turtlebot3_slam turtlebot3_slam.launch slam_methods:=gmapping

zotac-d05@d05:~$ rostopic echo /amcl_pose | sed -n -e '/pose:/,+10p'
pose:
pose:
position:
x: 2.6776955645384244
y: 0.006516339994905264
z: 0.0
orientation:
x: 0.0
y: 0.0
z: 0.04651613535574757
w: 0.9989175387145657
roslaunch halc_simulation turtlebot3_gazebo_halc.launch
roslaunch turtlebot3_navigation turtlebot3_navigation.launch map_file:=$HOME/catkin_ws/src/halc_simulation/map/halc_map.yaml
rostopic echo /move_base/status | sed -n -e ‘/seq:/p’ -e ‘/status:/p’ -e ‘/text:/p’
zotac-d05@d05:~/catkin_ws/src/halc_simulation$
rosrun halc_simulation megarover_sequence_goals.py goal_halc_3.yaml
roslaunch turtlebot3_gazebo turtlebot3_square_world.launch
roslaunch turtlebot3_slam turtlebot3_slam.launch slam_methods:=gmapping
roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch
Control Your TurtleBot3!
---------------------------
Moving around:
w
a s d
x
the robot and lidar info go different direction…
try running the command from the tutorial…
ROS演習8-2019:地図作成・自己位置推定 (gmapping, amcl)
https://demura.net/education/16294.html
zotac-d05@d05:~$ roslaunch turtlebot3_gazebo turtlebot3_fmt_world.launch ... logging to /home/zotac-d05/.ros/log/c07d07c4-fca8-11ef-89bd-9985b327fdea/roslaunch-d05-17171.log Checking log directory for disk usage. This may take a while. Press Ctrl-C to interrupt Done checking log file disk usage. Usage is <1GB. RLException: Invalid <param> tag: Cannot load command parameter [robot_description]: no such command [['/opt/ros/noetic/share/xacro/xacro.py', '/home/zotac-d05/catkin_ws/src/turtlebot3/turtlebot3_description/urdf/turtlebot3_waffle_pi.urdf.xacro']]. Param xml is <param name="robot_description" command="$(find xacro)/xacro.py $(find turtlebot3_description)/urdf/turtlebot3_$(arg model).urdf.xacro"/> The traceback for the exception was written to the log file
go back to the tutorial
ROS演習7-2019:デッドレコニングを実装しよう!
https://demura.net/education/16291.html
$ roslaunch turtlebot3_gazebo turtlebot3_empty_world.launch$ roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch$ rosrun my_odom3 my_odom3[ INFO] [1741500724.826418003]: Vel (Linear:0.000000, Angular:0.000000)
[ INFO] [1741500724.826487416]: Whell Pos (r:6.116184, l:6.116184)
[ INFO] [1741500724.866283956]: Whell Pos (r:6.116184, l:6.116184)
[ INFO] [1741500724.866399997]: Seq: 2666
[ INFO] [1741500724.866445659]: /odom Pos (x:0.201834, y:0.000000, z:0.000000)
[ INFO] [1741500724.866494649]: /odom Pose (roll:0.000000, pitch:-0.000000, yaw:0.000000)
ros::Subscriber sub = nh.subscribe("/cmd_vel", 10, cbVel);
ros::Subscriber sub2 = nh.subscribe("/odom", 100, cbOdom);
ros::Subscriber sub3 = nh.subscribe("/gazebo/model_states", 100, cbModelStates);
ros::Subscriber sub4 = nh.subscribe("/joint_states", 100, cbMyOdom);as the below command run with out problem, so refer its launch file
zotac-d05@d05:~$ roslaunch turtlebot3_gazebo turtlebot3_world.launch
change from
<param name="robot_description" command="$(find xacro)/xacro.py $(find turtlebot3_description)/urdf/turtlebot3_$(arg model).urdf.xacro" />
to (xacro has no .py)
<param name="robot_description" command="$(find xacro)/xacro --inorder $(find turtlebot3_description)/urdf/turtlebot3_$(arg model).urdf.xacro" />
note that there are turtlebot3_fmt_world.launch file, fmt.world file and fmt model file.


then try the program again
roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch
roslaunch turtlebot3_gazebo turtlebot3_fmt_world.launch
roslaunch turtlebot3_slam turtlebot3_slam.launch slam_methods:=gmapping
no problem!!!
then fixed the robot and sensor orientation!

somehow just copy camera pose from map7f.world to 01_square_world.world fixed the orientation problem…
<camera name='user_camera'>
<pose>-5.44095 3.17636 35.0543 0 1.51164 -0.686989</pose>
note that I cannot add the world_name parameter through the launch file..
roslaunch turtlebot3_gazebo turtlebot3_empty_world.launch world_name:=/home/zotac-d05/catkin_ws/src/turtlebot3_simulations/turtlebot3_gazebo/worlds/turtlebot3_world.world fail
cd ~/catkin_ws/src/turtlebot3_simulations/turtlebot3_gazebo/worlds/
roslaunch turtlebot3_gazebo turtlebot3_empty_world.launch world_name:=turtlebot3_world.world fail
need to create a new launch file when has a new map
roslaunch turtlebot3_gazebo turtlebot3_world.launch ok
ps. wanna do this.. as the robot control code
sudo apt-get install ros-noetic-turtlebot3-*

zotac-d05@d05:~$ rospack find turtlebot3_gazebo /home/zotac-d05/catkin_ws/src/turtlebot3_simulations/turtlebot3_gazebo



zotac-d05@d05:~/catkin_ws/src/my_gazebo_world/worlds$ gazebo 02_map_world Error [parser.cc:775] No <model> element in configFile[/home/zotac-d05/.gazebo/models/my_ground_plane/model.config] Error Code 12 Msg: Unable to resolve uri[model://my_ground_plane] to model path [/home/zotac-d05/.gazebo/models/my_ground_plane] since it does not contain a model.config file.

Move 01_square_world to ~/catkin_ws/src/turtlebot3_simulations/turtlebot3_gazebo/worlds/01_square_world.world
Create turtlebot3_square_world.launch in turtlebot3_square_world.launch

empty.world
fmt.world
turtlebot3_autorace_2020.world
turtlebot3_autorace.world
turtlebot3_house.world
turtlebot3_stage_1.world
turtlebot3_stage_2.world
turtlebot3_stage_3.world
turtlebot3_stage_4.world
turtlebot3_world.world





Onenote
Microsoft Loop
Notion.so
Obsidian
Notable : import md file, export html,md,pdf
Joblin
Scrapbox.io
เริ่มจากอ่านหนังสือเกี่ยวกับ pointcloud processing ถึงส่วนของ feature extraction แล้วเค้าพูดถึง Harris corner detector ใน image processing (pointcloud ใช้ Harris3d)
ก็เลยเสิร์จอ่านเรื่อง Harris corner detector ไปโผล่เว็บ opencv ไปเจอ sobel operator (คุ้นๆ) แล้วก็อ่านไปเรื่อยๆไปเจอคำว่า convolution คุ้นๆ แต่นึกไม่ออก อ่านไปอ่านมาก็อ้อ ใช้ใน CNN convolution neuron network ลืมไปได้ยังไง


ภาพบน convolution ของ image (discrete)
คือมี image f (มอง pixel x,y เป็น matrix ) กับ kernel/operator/filter y (matrix 3*3/5*5)
แล้วเราก็เอา kernel ไปวน convolution ทั่ว image เพื่อสร้าง image ใหม่
เช่น blur image ใช้ gaussian operator, edge image ใช้ sobel operator
ภาพล่าง convolution ของ signal (continuous) คือเปลี่ยนจาก ซิกม่าเป็นอินทิเกรต
แล้ว derivative มาจากไหน คือมันคุ้นๆว่า เวลาหา edge ของ image อะ มัน diff หาความเปลี่ยนแปลงของ pixel รอบๆ ถ้าค่า pixel ต่างกันมาก คือตรงนั้นมี edge

Sobel operator is a popular edge-detection filter that approximates the first derivative of the image. There are two Sobel kernels, one for detecting horizontal edges and one for vertical edges:
chatgpt
อ้อออ sobel operator คือเอามาใช้แทนการ diff ได้นี่เอง
แล้วก็ยังมี laplacian filter

the Laplacian filter approximates the second derivative and is used to detect areas of rapid intensity change (like edges).
chatgpt
คือไปอ่านเรื่องข้างบนนี้มา กับ กบก็พึ่งอ่านหนังสือ calculus จบไป เลยนึกขึ้นได้ว่าเรื่อง diff มันมีคำ 2 คำ ที่ความหมายคือการ diff นี่แหละ แต่ต่างกันยังไงไม่รู้
derivative (n/adj) represents the rate of change of a function at a particular point.
อัตราการเปลี่ยนแปลง ณ จุดๆนึง นี่เอง
differentiate (v) is the process of finding the derivative of a function.
ก็คือการคำนวณ diff
ปล. ย้อนไปที่ Harris corner detector ไปอ่านหลักการมัน (ซึ่งยังไม่เข้าใจ) มีพูดถึง Taylor expansion ก็ไปถามchatดู

the Harris corner detector uses a second-order Taylor expansion to model how the intensity of an image changes in the local neighborhood around each pixel
chatgpt
อ้อออ Harris corner detector ใช้ Taylor expansion ขั้นที่สองด้วยนะ ในการหาว่า pixel ณ จุดนั้นๆ มีความแตกต่างจาก pixel โดยรอบแค่ไหน (เพื่อเอาไประบุ corner จาก eigenvalues ของ Matrix M)
ไปต่อกันที่ Taylor expansion มันเอาไป ใช้ในการเขียนสมการ(ประมาณค่า) ของฟังก์ชันที่ซับซ้อน เช่น sin(x), e^x



ไม่ค่อยเข้าใจละ ไว้เจอกันรอบหน้าค่อยมาอ่านอีกรอบละกัน
คือว่า โปรแกรมpdf24เมื่อกี้มันพัง… พอinput pdfหลายๆไฟล์พร้อมกัน มันบอกว่าหา imageที่extractแล้วเก็บไว้ใน tmp folder ไม่เจอ .. ซึ่งปิดโปรแกรมเปิดใหม่ก็ไม่หาย เหมือนจะต้องรีเซ็ตคอม…
ก็เลย ถาม chatpgtให้มันเขียนโค๊ดให้หน่อย + แก้เองเยอะอยู่
ได้ความว่า
import fitz # pip install PyMuPDF
import os
import shutil
from pathlib import Path
def extract_images_from_pdf(pdf_path, save_folder):
doc = fitz.open(pdf_path)
print(pdf_path)
save_prefix = "_".join(element[:10] for element in pdf_path.split("\\"))
#save_prefix = pdf_path.replace("\\", "-")[0:20]
print(save_prefix)
img_index =0
for page_number in range(doc.page_count):
page = doc[page_number]
images = page.get_images(full=True)
#print("found images "+len(images))
for img_info in images:
img_index += 1
image_index = img_info[0]
#print(img_index,image_index)
base_image = doc.extract_image(image_index)
image_bytes = base_image["image"]
image_filename = f"{save_folder}/{save_prefix}_{img_index}.jpg"
with open(image_filename, "wb") as image_file:
image_file.write(image_bytes)
print("extracted images = "+str(img_index)+"\n")
doc.close()
def extract_images_from_pdfs(pdf_folder, save_folder):
files = [f for f in os.listdir(pdf_folder) if os.path.isfile(os.path.join(pdf_folder, f))]
for file in files:
#print(file)
if file.lower().endswith(('.pdf')):
filepath = os.path.join(pdf_folder, file)
extract_images_from_pdf(filepath, save_folder)
print("Done!")
extract_images_from_pdfs('Session 5 - Interfaces for the Body and Beyond','extracted_images')คือใส่ชื่อ folder เป็น input แล้วอ่าน pdf ในโฟล์เดอร์นั้น extract image
ซึงอันนี้ ถ้ารูปต้นฉบับเป็น transparent มา มันจะใส่ background สีดำให้ ต่างกับตัวโปรแกรมpdf24 ที่เซฟเป็นสีขาวให้ ดูคลีนตากว่า

ละก็contrastสีเพี้ยนน ไม่รู้ว่ารูปต้นฉบับเป็นไฟล์อะไร

folder ismar นี่ล่มมาก ทั้งสีเพี้ยน ภาพมาเป็นเศษๆ ไม่รู้เป็นไร

กับอีกอย่างที่ยังทำไม่ได้คือ ถ้ารูปต้นฉบับ embed เป็น pdf มา (มักจะเป็นพวกกราฟที่อยากได้ …) ทั้งโปรแกรมpdf24 ทั้ง python lib ตัวนี้ยัง extract ออกมาให้ไม่ได้
พอดีจะหาไอเดียทำกราฟใส่เปเปอร์ ปกติก็จะนั่งเปิดอ่านทีละอัน นั่งcropอันที่ชอบละsaveเก็บไว้ในfolderบ้าง แปะใน powerpoint/excel บ้างแล้วแต่อารมณ์ เสร็จละก็มักจะหาไม่เจอว่ารูปนี้มาจากเปเปอร์ไหน….
ด้วยความขี้เกียจcropรูปละ เลยเซิร์จหาโปรแกรมละก็เจอ มีให้ดาวโหลดโปรแกรมลงคอมด้วยนะ
https://tools.pdf24.org/en/extract-images
คือลากไฟล์เยอะๆใส่ได้เลย ละมันจะextractรูปภาพออมาให้ ตอนที่เซฟยังแยกโฟลเดอร์ตามชื่อ paper อยู่ โชคดีที่ชื่อรูปยังมี prefix เป็นชื่อโฟลเดอร์อยู่ (ถ้าทำในเว็ป ชื่อรูปไม่มี prefix เป็น 0.png 1.png 2.png ไป)
เดี่ยวเขียน python ให้มันเอารูปออกมาจากโฟลเดอร์จะได้ดูง่ายๆ ถาม chatgpt กับเขียนเพิ่มเองอีกนิด


import os
import shutil
from pathlib import Path
def move_images_and_delete_folders(folder_path):
print("process on :"+folder_path)
# Get a list of all subdirectories
subdirectories = [f for f in os.listdir(folder_path) if os.path.isdir(os.path.join(folder_path, f))]
# Iterate through each subdirectory
for subdir in subdirectories:
print(subdir)
subdir_path = os.path.join(folder_path, subdir)
if not os.path.isdir(subdir_path):
print("not a directory, skip!")
continue
# Get a list of all files in the subdirectory
files = [f for f in os.listdir(subdir_path) if os.path.isfile(os.path.join(subdir_path, f))]
folder_contain_image = False
# Iterate through each file in the subdirectory
for file in files:
# Check if the file is an image (you can customize this check based on your file extensions)
if file.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp')):
# Move the image file to the parent directory
source_file = os.path.join(subdir_path, file)
destination_file = os.path.join(folder_path, file)
shutil.move(source_file, destination_file)
folder_contain_image=True
# Delete the empty subdirectory
if(folder_contain_image):
os.rmdir(subdir_path)
# Replace 'your_folder_path' with the path to the folder containing subfolders
folder_path = os.getcwd()
move_images_and_delete_folders(folder_path)