Last active
May 7, 2024 20:34
-
-
Save nullmastermind/5a91c607bb614c537008abc8b474805a to your computer and use it in GitHub Desktop.
Rust Valorant color aimbot - Yellow (Protanopia) (recommend fov < 128)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fn get_move_value(&mut self, is_trigger_bot: bool) -> Point { | |
if !is_trigger_bot { | |
let current_frame_id = self.latest_frame_id.lock().unwrap().clone(); | |
if current_frame_id == self.current_frame_id { | |
return Point::new(0, 0); | |
} | |
self.current_frame_id = current_frame_id; | |
} | |
let current_frame = self.latest_frame.lock().unwrap().clone(); | |
if current_frame.is_none() { | |
return Point::new(0, 0); | |
} | |
let mut current_frame = current_frame.unwrap(); | |
if is_trigger_bot { | |
// current_frame = Mat::roi( | |
// ¤t_frame, | |
// Rect::new( | |
// 0, | |
// self.my_app.cheat_data.cap_h / 2 - 5, | |
// self.my_app.cheat_data.cap_w, | |
// 10, | |
// ), | |
// ) | |
// .unwrap(); | |
} | |
let closest_point = image_processing::find_closest(&mut current_frame, self.my_app.cheat_data.padding_bottom); | |
if closest_point.is_err() { | |
println!("find_closest error: {:?}", closest_point.err()); | |
let image_path = format!("images/{}.png", Instant::now().elapsed().as_millis()); | |
imwrite(&image_path, ¤t_frame, &Vector::new()).unwrap(); | |
return Point::new(0, 0); | |
} | |
let closest_point = closest_point.unwrap(); | |
if closest_point.x != -1 && closest_point.y != -1 { | |
let center_screen = Point::new(current_frame.cols() / 2, current_frame.rows() / 2); | |
let move_value = Point::new(closest_point.x - center_screen.x, closest_point.y - center_screen.y); | |
// if !is_trigger_bot { | |
// println!( | |
// "relative: {:?}", | |
// (*self.mouse.relative_value.lock().unwrap()).get_relative() | |
// ); | |
// } | |
return move_value; | |
} | |
Point::new(0, 0) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::cmp::{max, min}; | |
use std::ops::Sub; | |
use opencv::core::{ | |
bitwise_and, count_non_zero, find_non_zero, in_range, mean, no_array, Point, Rect, Scalar, Size, Vec3b, Vector, | |
BORDER_CONSTANT, | |
}; | |
use opencv::imgproc::*; | |
use opencv::prelude::*; | |
use opencv::types::{VectorOfPoint, VectorOfVectorOfPoint}; | |
const GROW_VALUE_W: i32 = 8; | |
const GROW_VALUE_H: i32 = 8; | |
pub fn calc_percent_non_black_pixels(mat: &Mat) -> anyhow::Result<f32> { | |
// Convert the input matrix to grayscale | |
let mut gray_result = Mat::default(); | |
cvt_color(mat, &mut gray_result, COLOR_BGR2GRAY, 0)?; | |
// Calculate the total number of pixels | |
let total_pixels = gray_result.cols() * gray_result.rows(); | |
// Count the number of non-black pixels | |
let non_black_pixels = count_non_zero(&gray_result)?; | |
// Calculate the percentage of non-black pixels | |
let percent_non_black_pixels = non_black_pixels as f32 / total_pixels as f32 * 100.0; | |
Ok(percent_non_black_pixels) | |
} | |
pub fn process_box(rgb_mat: &Mat) -> anyhow::Result<(f32, Mat)> { | |
// let mut bgr_mat = Mat::default(); | |
// cvt_color(&rgb_mat, &mut bgr_mat, COLOR_RGB2BGR, 0)?; | |
// let mut diff_mat = Mat::default(); | |
// absdiff(&rgb_mat, &bgr_mat, &mut diff_mat)?; | |
// let mut subtracted_mat = Mat::default(); | |
// subtract(&bgr_mat, &diff_mat, &mut subtracted_mat, &Mat::default(), -1)?; | |
let mut hsv_subtracted_mat = Mat::default(); | |
cvt_color(&rgb_mat, &mut hsv_subtracted_mat, COLOR_BGR2HSV, 0)?; | |
let mask_hsv = { | |
let lower = Scalar::new(20., 125., 150., 0.); | |
let upper = Scalar::new(40., 255., 255., 0.); | |
let mut mask = Mat::default(); | |
in_range(&hsv_subtracted_mat, &lower, &upper, &mut mask)?; | |
mask | |
}; | |
let mut dilated_mask_hsv = Mat::default(); | |
dilate( | |
&mask_hsv, | |
&mut dilated_mask_hsv, | |
&get_structuring_element(MORPH_RECT, Size::new(GROW_VALUE_W, GROW_VALUE_H), Point::new(-1, -1))?, | |
Point::new(-1, -1), | |
1, | |
BORDER_CONSTANT, | |
Scalar::from(MORPH_RECT), | |
)?; | |
let mut outlined_image = Mat::default(); | |
bitwise_and(&rgb_mat, &rgb_mat, &mut outlined_image, &dilated_mask_hsv)?; | |
let mut lab_subtracted_mat = Mat::default(); | |
cvt_color(&rgb_mat, &mut lab_subtracted_mat, COLOR_BGR2Lab, 0)?; | |
let mask_lab = { | |
// let lower = Scalar::new(180., 0., 200., 0.); | |
// let upper = Scalar::new(255., 127., 255., 0.); | |
let lower = Scalar::new(200., 80., 200., 0.); | |
let upper = Scalar::new(255., 130., 255., 0.); | |
let mut mask = Mat::default(); | |
in_range(&lab_subtracted_mat, &lower, &upper, &mut mask)?; | |
mask | |
}; | |
let mut dilated_mask_lab = Mat::default(); | |
dilate( | |
&mask_lab, | |
&mut dilated_mask_lab, | |
&get_structuring_element( | |
MORPH_RECT, | |
Size::new(GROW_VALUE_W * 2, GROW_VALUE_H * 2), | |
Point::new(-1, -1), | |
)?, | |
Point::new(-1, -1), | |
1, | |
BORDER_CONSTANT, | |
Scalar::from(MORPH_RECT), | |
)?; | |
let mut result = Mat::default(); | |
bitwise_and(&outlined_image, &outlined_image, &mut result, &dilated_mask_lab)?; | |
Ok((calc_percent_non_black_pixels(&result)?, result)) | |
} | |
pub fn get_mat_from_contour(image: &Mat, contour: &Vector<Point>) -> anyhow::Result<Mat> { | |
// Create a blank image with the same shape as the input image | |
let mut mat = Mat::new_rows_cols_with_default(image.rows(), image.cols(), image.typ(), Scalar::all(0.0))?; | |
// Draw the contour on the blank image | |
let contour_mat = Mat::from_slice_2d(&[contour])?; | |
draw_contours( | |
&mut mat, | |
&contour_mat, | |
0, | |
Scalar::all(255.0), | |
-1, | |
LINE_8, | |
&no_array(), | |
0, | |
Point::default(), | |
)?; | |
Ok(mat) | |
} | |
pub fn find_closest_non_black_pixel( | |
mat: &Mat, | |
percent: f32, | |
threshold: u8, | |
scan_radius: i32, | |
neighbor_percent: f32, | |
max_scan_time: i32, | |
) -> anyhow::Result<Option<Point>> { | |
let rows = mat.rows(); | |
let cols = mat.cols(); | |
let mut result = Point::new(-1, -1); | |
let neighbor_distance = max(min(34, (neighbor_percent * percent) as i32), 8); | |
let center = Point::new(cols / 2, rows / 2); | |
let height = mat.rows(); | |
let width = mat.cols(); | |
let mut closest_distance = f64::INFINITY; | |
let mut closest_pixel = Point::new(0, 0); | |
// Find the indices where any of the channels exceed the threshold | |
let mut indices = Vec::new(); | |
for y in 0..height { | |
for x in 0..width { | |
let pixel = mat.at_2d::<Vec3b>(y, x); | |
if pixel.is_err() { | |
return Ok(None); | |
} | |
let pixel = pixel?; | |
if pixel[0] > threshold || pixel[1] > threshold || pixel[2] > threshold { | |
indices.push(Point::new(x, y)); | |
} | |
} | |
} | |
// Iterate over the indices and calculate the distance | |
for point in &indices { | |
let distance = center.sub(*point).norm(); | |
if distance < closest_distance { | |
closest_distance = distance; | |
closest_pixel = *point; | |
} | |
} | |
if closest_pixel != Point::new(0, 0) { | |
let mut neighbor_pixels = Vec::new(); | |
// scan min y pixel | |
for _ in 0..max_scan_time { | |
let scan_from_point = if closest_pixel != Point::new(0, 0) { | |
closest_pixel | |
} else { | |
center | |
}; | |
let mut min_y = f64::INFINITY; | |
let mut min_y_point = Point::new(0, 0); | |
for point in &indices { | |
let x = point.x; | |
let y = point.y; | |
if x >= scan_from_point.x - scan_radius && x <= scan_from_point.x + scan_radius { | |
if y >= scan_from_point.y - scan_radius && y <= scan_from_point.y + scan_radius { | |
if y < min_y as i32 { | |
min_y = y as f64; | |
min_y_point = *point; | |
} | |
} | |
} | |
} | |
if min_y_point != Point::new(0, 0) { | |
closest_pixel = min_y_point; | |
} else { | |
break; | |
} | |
} | |
// Loop through the neighbor pixels within the specified distance | |
for y in closest_pixel.y - neighbor_distance..=closest_pixel.y + neighbor_distance { | |
for x in closest_pixel.x - neighbor_distance..=closest_pixel.x + neighbor_distance { | |
if x >= 0 && x < width && y >= 0 && y < height { | |
let pixel = mat.at_2d::<Vec3b>(y, x)?; | |
if pixel[0] > threshold || pixel[1] > threshold || pixel[2] > threshold { | |
neighbor_pixels.push(Point::new(x, y)); | |
} | |
} | |
} | |
} | |
// Calculate the center coordinates of the neighbor pixels | |
if !neighbor_pixels.is_empty() { | |
let neighbor_x: Vec<i32> = neighbor_pixels.iter().map(|p| p.x).collect(); | |
let neighbor_y: Vec<i32> = neighbor_pixels.iter().map(|p| p.y).collect(); | |
let center_x = neighbor_x.iter().sum::<i32>() / neighbor_x.len() as i32; | |
let avg_center_y = neighbor_y.iter().sum::<i32>() / neighbor_y.len() as i32; | |
let mut center_y = neighbor_y[0]; | |
for i in 1..neighbor_y.len() { | |
if neighbor_y[i] < center_y { | |
center_y = neighbor_y[i]; | |
} | |
} | |
center_y = ((avg_center_y + center_y) / 2) as i32; | |
let center_pixel = Point::new(center_x, center_y); | |
result.x = center_pixel.x; | |
result.y = center_pixel.y; | |
} | |
} | |
if result.x != -1 && result.y != -1 { | |
Ok(Some(result)) | |
} else { | |
Ok(None) | |
} | |
} | |
pub fn create_ellipse_mask(mat: &Mat) -> anyhow::Result<Mat> { | |
let (height, width) = (mat.rows(), mat.cols()); | |
// Create a black image with the same size and type as the input image | |
let mut mask = Mat::new_rows_cols_with_default(height, width, Mat::default().typ(), Scalar::all(0.0))?; | |
// Calculate the center coordinates of the ellipse | |
let center = Point::new(width / 2, height / 2); | |
// Calculate the axes lengths of the ellipse | |
let axes = Size::new((width as f32 / 1.7) as i32, (height as f32 / 2.3) as i32); | |
// Draw the ellipse on the mask | |
ellipse( | |
&mut mask, | |
center, | |
axes, | |
0.0, | |
0.0, | |
360.0, | |
Scalar::all(255.0), | |
-1, | |
FILLED, | |
0, | |
)?; | |
// Apply the mask to the input image | |
let mut result = Mat::default(); | |
bitwise_and(mat, mat, &mut result, &mask)?; | |
Ok(result) | |
} | |
pub fn find_closest(mat: &mut Mat, padding_bottom: Option<i32>) -> anyhow::Result<Point> { | |
// let ellipse_mat = create_ellipse_mask(mat)?; | |
// let mat = match is_trigger_bot { | |
// true => mat, | |
// false => &ellipse_mat, | |
// }; | |
// let center = Point::new(mat.cols() / 2, mat.rows() / 2); | |
if let Some(padding) = padding_bottom { | |
if padding > 0 { | |
let height = mat.rows(); | |
let width = mat.cols(); | |
let rectangle_height = height - padding; | |
let rect = Rect::new(0, rectangle_height, width, height); | |
let color = Scalar::new(0.0, 0.0, 0.0, 0.0); // Black color | |
rectangle(mat, rect, color, -1, LINE_8, 0)?; | |
} | |
} | |
let mut closest_points = vec![]; | |
let (percent, processed_mat) = process_box(&mat)?; | |
closest_points.push(find_closest_by_box(&processed_mat, percent)?); | |
let mut min_distance = f64::MAX; | |
let mut closest_point = Point::new(-1, -1); | |
// let y_scaling_factor = 1.3; | |
for i in 0..closest_points.len() { | |
let point = closest_points[i]; | |
if point.x == -1 || point.y == -1 { | |
continue; | |
} | |
// let dx = (point.x - center.x) as f64; | |
// let dy = (point.y - center.y) as f64 * y_scaling_factor; | |
// let distance = dx * dx + dy * dy; | |
// TODO: by high | |
let distance = point.y as f64; | |
if distance < min_distance { | |
min_distance = distance; | |
let mut new_point = point.clone(); | |
if closest_point.x != -1 { | |
if i32::abs(point.x - closest_point.x) <= 21 { | |
if closest_point.y < point.y { | |
new_point = closest_point.clone(); | |
} | |
} | |
} | |
closest_point = new_point; | |
} | |
} | |
Ok(closest_point) | |
} | |
pub fn find_closest_by_box(processed_mat: &Mat, percent: f32) -> anyhow::Result<Point> { | |
let fast_result = find_closest_non_black_pixel(processed_mat, percent, 20, 20, 45.0, 3)?; | |
if fast_result.is_none() { | |
return Ok(Point::new(-1, -1)); | |
} | |
let fast_result = fast_result.unwrap(); | |
let center = Point::new(fast_result.x, fast_result.y); | |
let mut mask = Mat::default(); | |
cvt_color(processed_mat, &mut mask, COLOR_BGR2GRAY, 0)?; | |
let mut contours = VectorOfVectorOfPoint::new(); | |
find_contours( | |
&mask, | |
&mut contours, | |
RETR_EXTERNAL, | |
CHAIN_APPROX_SIMPLE, | |
Point::default(), | |
)?; | |
let mut parent_contours = VectorOfVectorOfPoint::new(); | |
let mut closest_contour = VectorOfPoint::new(); | |
let mut min_distance = f64::INFINITY; | |
for contour in contours.iter() { | |
let bounding_rect = bounding_rect(&contour)?; | |
let x = bounding_rect.x; | |
let y = bounding_rect.y; | |
let w = bounding_rect.width; | |
let h = bounding_rect.height; | |
if w < 2 { | |
continue; | |
} | |
let distance = (((center.x - (x + w / 2)).pow(2) + (center.y - (y + h / 2)).pow(2)) as f64).sqrt(); | |
if distance < min_distance { | |
min_distance = distance; | |
closest_contour = contour.clone(); | |
} | |
if x <= center.x && center.x <= x + w && y <= center.y && center.y <= y + h { | |
parent_contours.push(contour.clone()); | |
} | |
} | |
if !parent_contours.is_empty() { | |
min_distance = f64::INFINITY; | |
for contour in parent_contours.iter() { | |
let bounding_rect = bounding_rect(&contour)?; | |
let x = bounding_rect.x; | |
let y = bounding_rect.y; | |
let w = bounding_rect.width; | |
let h = bounding_rect.height; | |
if w < 2 { | |
continue; | |
} | |
let distance = (((center.x - (x + w / 2)).pow(2) + (center.y - (y + h / 2)).pow(2)) as f64).sqrt(); | |
if distance < min_distance { | |
min_distance = distance; | |
closest_contour = contour.clone(); | |
} | |
} | |
} | |
if !closest_contour.is_empty() { | |
let bounding_rect = bounding_rect(&closest_contour)?; | |
let y = bounding_rect.y; | |
let w = bounding_rect.width - GROW_VALUE_W * 2; | |
let h = bounding_rect.height; | |
let closest_contour_mat = get_mat_from_contour(processed_mat, &closest_contour)?; | |
let to_y = min((w as f32 / 3.) as i32, h / 2) + (GROW_VALUE_H as f64 / 2.) as i32; | |
let limit_y = y + to_y; | |
let mut closest_contour_mat_gray = Mat::default(); | |
cvt_color(&closest_contour_mat, &mut closest_contour_mat_gray, COLOR_BGR2GRAY, 0)?; | |
let non_black_pixels = closest_contour_mat_gray.row(limit_y)?; | |
let mut threshold_non_black_pixels = Mat::default(); | |
threshold( | |
&non_black_pixels, | |
&mut threshold_non_black_pixels, | |
0.0, | |
255.0, | |
THRESH_BINARY, | |
)?; | |
if count_non_zero(&threshold_non_black_pixels)? > 0 { | |
let mut avg_non_black_pixel_index = Mat::default(); | |
find_non_zero(&closest_contour_mat_gray.row(limit_y)?, &mut avg_non_black_pixel_index)?; | |
let avg_non_black_pixel_x = mean(&avg_non_black_pixel_index, &no_array())?[0]; | |
return Ok(Point::new(avg_non_black_pixel_x as i32, limit_y)); | |
} | |
return Ok(Point::new(fast_result.x, limit_y)); | |
} | |
return Ok(Point::new(-1, -1)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment