Skip to content

Commit

Permalink
Second commit
Browse files Browse the repository at this point in the history
  • Loading branch information
wormtql committed Oct 6, 2021
1 parent 6909471 commit 0ae7bb7
Show file tree
Hide file tree
Showing 9 changed files with 314 additions and 81 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ data/
target/
mona.json
.idea/
captures/
52 changes: 52 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ regex = "1.5.4"
log = "0.4.14"
env_logger = "0.9.0"
edit-distance = "2.1.0"
clap = "2.33.3"

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winuser", "winbase", "wingdi", "winnt", "securitybaseapi"] }
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<div align="center">

# Yas
Yet Another Genshin Impact Scanner
又一个原神圣遗物导出器

</div>

## 介绍
基于CRNN(MobileNetV3_Small + LSTM)字符识别模型,使用原神字体对原神中会出现的字符串进行训练,达到更高的速度和更精确的结果。
导出结果可以导入分析工具(例如 [莫娜占卜铺](https://mona-uranai.com/) )进行配装或者其他计算
由于使用了 [Rust](https://www.rust-lang.org/) 进行编写,运行效率和文件体积都得到了很大的提升
### 相关资料
- [MobileNetV3](https://arxiv.org/pdf/1905.02244.pdf)
- [CRNN](https://arxiv.org/pdf/1507.05717.pdf)

## 使用
- 打开原神,并切换到背包页面,将背包拉到最上面
- 下载单exe可执行文件,右键管理员运行

### 命令行使用
查看选项
```shell
yas --help
```
只扫描五星圣遗物
```shell
yas --min-star=5
```
只扫描一行
```shell
yas --max-row=1
```

## 反馈
- Issue
- QQ群:801106595
16 changes: 12 additions & 4 deletions src/capture/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@ use std::os::windows::ffi::OsStrExt;
use std::ptr::null_mut;
use std::mem::size_of;

use winapi::um::winuser::{FindWindowW, GetDC, GetClientRect, SetForegroundWindow};
use winapi::shared::windef::{HWND, HDC, RECT, HBITMAP};
use winapi::um::winuser::{
FindWindowW,
GetDC,
ReleaseDC,
SetThreadDpiAwarenessContext,
GetClientRect,
SetForegroundWindow
};
use winapi::shared::windef::{HWND, HDC, RECT, HBITMAP, DPI_AWARENESS_CONTEXT};
use winapi::shared::ntdef::NULL;
use winapi::um::wingdi::{
CreateCompatibleDC,
DeleteObject,
BitBlt,
SRCCOPY,
CreateCompatibleBitmap,
Expand All @@ -30,12 +38,12 @@ use image::ImageBuffer;

use crate::common::{PixelRect, PixelRectBound};
use crate::common::color::Color;
use self::winapi::um::wingdi::DeleteObject;
use self::winapi::um::winuser::ReleaseDC;
use winapi::shared::windef::DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE;


#[cfg(windows)]
unsafe fn unsafe_capture(rect: &PixelRect) -> Result<Vec<u8>, String> {
SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
// let dc_screen: HDC = GetDC(null_mut());
// let dc_window: HDC = GetDC(handle);
let dc_window: HDC = GetDC(null_mut());
Expand Down
51 changes: 51 additions & 0 deletions src/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use crate::inference::pre_process::{pre_process, to_gray, raw_to_img};
use crate::info::info::ScanInfo;
use image::{GrayImage, RgbImage};
use crate::capture::capture_absolute;
use std::time::SystemTime;
use log::{info};

pub mod utils;
pub mod buffer;
Expand All @@ -16,6 +18,15 @@ pub struct PixelRect {
pub height: i32,
}

impl PixelRect {
pub fn scale(&mut self, ratio: f64) {
self.left = (self.left as f64 * ratio).round() as i32;
self.top = (self.top as f64 * ratio).round() as i32;
self.width = (self.width as f64 * ratio).round() as i32;
self.height = (self.height as f64 * ratio).round() as i32;
}
}

#[derive(Clone, Debug)]
pub struct PixelRectBound {
pub left: i32,
Expand Down Expand Up @@ -49,9 +60,12 @@ impl PixelRectBound {
width: w,
height: h,
};
let now = SystemTime::now();
let raw_u8 = capture::capture_absolute(&rect).unwrap();
info!("capture raw time: {}ms", now.elapsed().unwrap().as_millis());
let raw_gray = to_gray(raw_u8, w as u32, h as u32);
let raw_after_pp = pre_process(raw_gray);
info!("preprocess time: {}ms", now.elapsed().unwrap().as_millis());
Ok(raw_after_pp)
}

Expand All @@ -75,10 +89,47 @@ pub struct RawImage {
pub h: u32,
}

pub struct RawCaptureImage {
pub data: Vec<u8>,
pub w: u32,
pub h: u32,
}

impl RawImage {
pub fn to_gray_image(&self) -> GrayImage {
raw_to_img(&self)
}
}

impl RawCaptureImage {
pub fn crop_and_preprocess(&self, rect: &PixelRect) -> RawImage {
// let now = SystemTime::now();
let vol = rect.width * rect.height;
let mut data = vec![0.0; vol as usize];
for i in rect.left..rect.left + rect.width {
for j in rect.top..rect.top + rect.height {
let x = i;
let y = self.h as i32 - j - 1;
let b: u8 = self.data[((y * self.w as i32 + x) * 4) as usize];
let g: u8 = self.data[((y * self.w as i32 + x) * 4 + 1) as usize];
let r: u8 = self.data[((y * self.w as i32 + x) * 4 + 2) as usize];

let gray = r as f32 * 0.2989 + g as f32 * 0.5870 + b as f32 * 0.1140;
let new_index = ((j - rect.top) * rect.width + i - rect.left) as usize;
data[new_index] = gray;
}
}

let im = RawImage {
data,
w: rect.width as u32,
h: rect.height as u32,
};
let im = pre_process(im);
// info!("preprocess time: {}ms", now.elapsed().unwrap().as_millis());
// im.to_gray_image().save("test.png");
im
}
}

// pub struct
6 changes: 5 additions & 1 deletion src/info/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub struct ScanInfo {
pub main_stat_name_position: PixelRectBound,
pub main_stat_value_position: PixelRectBound,
pub level_position: PixelRectBound,
pub panel_position: PixelRectBound,

pub sub_stat1_position: PixelRectBound,
pub sub_stat2_position: PixelRectBound,
Expand Down Expand Up @@ -79,6 +80,7 @@ impl ScanInfo {
main_stat_name_position: my_get_rect((1099, 211, 1230, 247)),
main_stat_value_position: my_get_rect((1099, 247, 1243, 285)),
level_position: my_get_rect((1104, 359, 1147, 378)),
panel_position: my_get_rect((1077, 100, 1487, 800)),

sub_stat1_position: my_get_rect((1118, 398, 1377, 422)),
sub_stat2_position: my_get_rect((1118, 431, 1377, 454)),
Expand Down Expand Up @@ -132,6 +134,7 @@ impl ScanInfo {
main_stat_name_position: my_get_rect((990, 194, 1105, 223)),
main_stat_value_position: my_get_rect((990, 223, 1105, 262)),
level_position: my_get_rect((993, 323, 1032, 340)),
panel_position: my_get_rect((969, 90, 1338, 810)),

sub_stat1_position: my_get_rect((1006, 356, 1188, 383)),
sub_stat2_position: my_get_rect((1006, 385, 1188, 411)),
Expand All @@ -146,7 +149,7 @@ impl ScanInfo {
art_gap_x: get_scalar(17.0, w, width),
art_gap_y: get_scalar(17.0, h, height),

art_row: 5,
art_row: 6,
art_col: 7,

left_margin: get_scalar(155.0, w, width),
Expand Down Expand Up @@ -182,6 +185,7 @@ impl ScanInfo {
main_stat_name_position: my_get_rect((880, 175, 984, 200)),
main_stat_value_position: my_get_rect((880, 200, 970, 233)),
level_position: my_get_rect((883, 287, 916, 303)),
panel_position: my_get_rect((862, 80, 1189, 879)),

sub_stat1_position: my_get_rect((894, 320, 1054, 339)),
sub_stat2_position: my_get_rect((894, 345, 1054, 365)),
Expand Down
31 changes: 27 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ use yas::capture::{capture_absolute, capture_absolute_image};
use yas::inference::pre_process::{to_gray, raw_to_img, normalize, crop, pre_process, image_to_raw};
use yas::info::info;

use winapi::um::winuser::{SetForegroundWindow};
use winapi::um::winuser::{SetForegroundWindow, GetDpiForSystem, SetThreadDpiAwarenessContext, ShowWindow, SW_SHOW, SW_RESTORE};

use clap::{Arg, App};

use image::{ImageBuffer, Pixel};
use image::imageops::grayscale;
use yas::common::{RawImage, PixelRect};
use yas::scanner::yas_scanner::YasScanner;
use yas::scanner::yas_scanner::{YasScanner, YasScannerConfig};
use yas::inference::inference::CRNNModel;
use yas::expo::mona_uranai::MonaFormat;
use env_logger::{Env, Builder, Target};
use log::{info, LevelFilter};
use winapi::shared::windef::DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE;

fn open_local(path: String) -> RawImage {
let img = image::open(path).unwrap();
Expand All @@ -38,17 +41,37 @@ fn main() {
utils::error_and_quit("请以管理员身份运行该程序")
}

let matches = App::new("YAS - 原神圣遗物导出器")
.version("0.1.0")
.author("wormtql <[email protected]>")
.about("Genshin Impact Artifact Exporter")
.arg(Arg::with_name("max-row").long("max-row").takes_value(true).help("最大扫描行数"))
.arg(Arg::with_name("capture-only").long("capture-only").required(false).takes_value(false).help("只保存截图,不进行扫描,debug专用"))
.arg(Arg::with_name("min-star").long("min-star").takes_value(true).help("最小星级").min_values(1).max_values(5))
.arg(Arg::with_name("max-wait-switch-artifact").long("max-wait-switch-artifact").takes_value(true).min_values(10).help("切换圣遗物最大等待时间(ms)"))
.get_matches();
let config = YasScannerConfig::from_match(matches);

unsafe { SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE); }
let hwnd = match utils::find_window(String::from("原神")) {
Err(s) => {
utils::error_and_quit("未找到原神窗口,请确认原神已经开启");
},
Ok(h) => h,
};

unsafe { ShowWindow(hwnd, SW_RESTORE); }
// utils::sleep(1000);
unsafe { SetForegroundWindow(hwnd); }
utils::sleep(1000);

let rect = utils::get_client_rect(hwnd).unwrap();
let mut rect = utils::get_client_rect(hwnd).unwrap();

// rect.scale(1.25);
info!("detected left: {}", rect.left);
info!("detected top: {}", rect.top);
info!("detected width: {}", rect.width);
info!("detected height: {}", rect.height);

let mut info: info::ScanInfo;
if rect.height * 16 == rect.width * 9 {
Expand All @@ -61,7 +84,7 @@ fn main() {
utils::error_and_quit("不支持的分辨率");
}

let mut scanner = YasScanner::new(info.clone());
let mut scanner = YasScanner::new(info.clone(), config);

let now = SystemTime::now();
let results = scanner.start();
Expand Down
Loading

0 comments on commit 0ae7bb7

Please sign in to comment.