基于密度聚类算法的通用怪物定位实现
先上代码import cv2
import numpy as np
import wx
import wx.lib.scrolledpanel as scrolled
import wx.aui
from sklearn.cluster import DBSCAN
class MyFrame(wx.Frame):
def __init__(self, parent, title):
super(MyFrame, self).__init__(parent, title=title, size=(800, 600))
self.mgr = wx.aui.AuiManager(self)
# 创建第一个图片显示面板
panel1 = scrolled.ScrolledPanel(self, -1)
panel1.SetupScrolling()
image_path1 = "1.jpg"
self.image_bitmap1 = wx.Bitmap(image_path1, wx.BITMAP_TYPE_ANY)
self.static_bitmap1 = wx.StaticBitmap(panel1, -1, self.image_bitmap1, pos=(10, 10))
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.static_bitmap1, 0, wx.ALL, 5)
panel1.SetSizer(sizer)
self.mgr.AddPane(panel1, wx.aui.AuiPaneInfo().Caption("Image 1").Left().BestSize(400, 600))
self.Bind(wx.EVT_CONTEXT_MENU, self.on_context_menu)
# 创建第二个图片显示面板
panel2 = scrolled.ScrolledPanel(self, -1)
panel2.SetupScrolling()
self.image_bitmap2 = self.image_bitmap1# 直接从第一张图片获取数据
self.static_bitmap2 = wx.StaticBitmap(panel2, -1, self.image_bitmap2, pos=(10, 10))
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.static_bitmap2, 0, wx.ALL, 5)
panel2.SetSizer(sizer)
self.mgr.AddPane(panel2, wx.aui.AuiPaneInfo().Caption("Image 2").Right().BestSize(400, 600))
# 创建输入框面板
input_panel = wx.Panel(self)
input_panel.SetMinSize((400, 600))# 设置最小宽高为400x600
input_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.input1 = wx.TextCtrl(input_panel, -1, "")
self.input2 = wx.TextCtrl(input_panel, -1, "")
self.input3 = wx.TextCtrl(input_panel, -1, "")
self.output_button = wx.Button(input_panel, label="显示")
self.output_button.Bind(wx.EVT_BUTTON, self.on_output_button_click)
input_sizer.Add(self.input1, 0, wx.ALL, 5)
input_sizer.Add(self.input2, 0, wx.ALL, 5)
input_sizer.Add(self.input3, 0, wx.ALL, 5)
input_sizer.Add(self.output_button, 0, wx.ALL, 5)
input_panel.SetSizer(input_sizer)
self.mgr.AddPane(input_panel, wx.aui.AuiPaneInfo().Caption("Inputs").Bottom().BestSize(400, 50))
self.mgr.Update()
def on_context_menu(self, event):
menu = wx.Menu()
item = menu.Append(-1, "Replace Image")
self.Bind(wx.EVT_MENU, self.on_replace_image, item)
self.PopupMenu(menu)
menu.Destroy()
def on_replace_image(self, event):
with wx.FileDialog(self, "Choose a file", wildcard="All files (*.*)|*.*",
style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as fileDialog:
if fileDialog.ShowModal() == wx.ID_CANCEL:
return
pathname = fileDialog.GetPath()
self.update_image(pathname)
new_bitmap2 = wx.Bitmap(pathname, wx.BITMAP_TYPE_ANY)
self.image_bitmap2 = new_bitmap2
def update_image(self, image_path):
new_bitmap = wx.Bitmap(image_path, wx.BITMAP_TYPE_ANY)
self.static_bitmap1.SetBitmap(new_bitmap)
self.static_bitmap2.SetBitmap(new_bitmap)
def on_output_button_click(self, event):
input1_content = self.input1.GetValue()
input2_content = self.input2.GetValue()
input3_content = self.input3.GetValue()
# 获取第二张图片数据
image = self.bitmap_to_cv_image(self.image_bitmap2)
processed_img = self.Stressshow(image, input1_content)
processed_img = self.jl(processed_img, int(input2_content), int(input3_content))
# 清空第二张图片面板数据
self.static_bitmap2.SetBitmap(wx.Bitmap())
# 显示处理后的图片在第二个图片面板中
self.show_processed_image(processed_img, self.static_bitmap2)
def show_processed_image(self, processed_image, image_panel):
bitmap = self.cv_image_to_bitmap(processed_image)
image_panel.SetBitmap(bitmap)
def bitmap_to_cv_image(self, bitmap):
bmp = bitmap.ConvertToImage()
data = bmp.GetData()
image = np.frombuffer(data, dtype=np.uint8)
image = image.reshape(bmp.GetHeight(), bmp.GetWidth(), -1)
image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
return image
def cv_image_to_bitmap(self, image):
if len(image.shape) == 2:# 处理灰度图像
height, width = image.shape
cv2_image_rgb = cv2.cvtColor(image, cv2.COLOR_GRAY2RGB)# 将灰度图像转换为RGB格式
elif len(image.shape) == 3:# 处理彩色图像
height, width, _ = image.shape
cv2_image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)# 将BGR格式转换为RGB格式
else:
raise ValueError('Unsupported image format')
wx_image = wx.Image(width, height, cv2_image_rgb.tobytes())# 创建wx.Image对象
bitmap = wx.Bitmap(wx_image)# 将wx.Image转换为Bitmap对象
return bitmap
def jl(self, img, eps=7, min=60):
white_pixels = np.argwhere(img == 255)
# # 使用DBSCAN进行像素聚类
dbscan = DBSCAN(eps=eps, min_samples=min)
labels = dbscan.fit_predict(white_pixels)
for label in np.unique(labels):
if label == -1:
continue
cluster = white_pixels
x, y, w, h = cv2.boundingRect(cluster)
img = cv2.rectangle(img, (y, x), (y + h, x + w), (125, 0, 0), 2)
return img
def parse_custom_color(self, color_string):
r, g, b = int(color_string, 16), int(color_string, 16), int(color_string, 16)
if len(color_string) > 6:
dr, dg, db = int(color_string, 16), int(color_string, 16), int(color_string, 16)
else:
dr, dg, db = 0, 0, 0
lower_rgb = np.array(, dtype=np.uint8)
upper_rgb = np.array(, dtype=np.uint8)
return lower_rgb, upper_rgb
def Stressshow(self, img, colors):
colors = colors.split("|")
masks = np.zeros_like(img[:, :, 0], dtype=np.uint8)# 创建与图像大小相同的空白掩膜
for color in colors:
lower_rgb, upper_rgb = self.parse_custom_color(color)
mask = cv2.inRange(img, lower_rgb, upper_rgb)
masks += mask
# 将符合条件的颜色设为白色(255),不符合条件的设为黑色(0)
result = np.where(masks > 0, 255, 0).astype(np.uint8)
return result
app = wx.App(False)
frame = MyFrame(None, "My GUI")
frame.Show()
app.MainLoop()
再说一下原理:
首先呢,通过颜色的rgb值将怪物从地图上区分出来,那么受这个因素影响,怪物的颜色就不能和地图颜色太相近,要不然就分辨不出来。这里其实稍微做了一下优化,可以像大漠那样取多个点的颜色,也支持偏色。
然后呢,将怪物的颜色变为白色,将地图颜色变为黑色,这就可以把图像转换为一个二维数组了,直接进行数据处理。
接着呢,使用密度聚类算法筛选出符合条件的区域。这里关于密度聚类算法大家可以百度一下就能找到原理。
最后呢,我们需要传进去三个参数,一个是怪物的颜色描述,一个是密度聚类的半径大小,一个是密度聚类的点的数量,就看可以筛选出来怪物的位置。
这三个参数需要大家通过微调来实现精准控制。
讲一讲软件用法:
需要的库大家自行下载,直接运行会报错缺少图片,这个不影响,直接对最左边的窗口右键可以替换图片,然后在最下面的三个输入框输入我们需要的参数,点击按钮就可以在右边的窗口框选出结果。
因为论坛不支持bmp格式图片,就不附图了。 强悍,支持楼主,不知道有没有寻路的解决方案基于图色的!
页:
[1]