Skip to content

Instantly share code, notes, and snippets.

@nullmastermind
Last active May 7, 2024 20:34
Show Gist options
  • Save nullmastermind/5a91c607bb614c537008abc8b474805a to your computer and use it in GitHub Desktop.
Save nullmastermind/5a91c607bb614c537008abc8b474805a to your computer and use it in GitHub Desktop.
Rust Valorant color aimbot - Yellow (Protanopia) (recommend fov < 128)
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(
// &current_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, &current_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)
}
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