I am writing a autoclicker for one mobile game (screenshot below). The task is to find objects on the map. More precisely, the program makes a screenshot of the game running in the Bluestacks emulator, I get a bitmap , and I need to search for objects on the map by fragments in the screenshot. Tell me the algorithm for finding a fragment in the image?

enter image description here

  • The live clicker is called Mod CoC :) there is on Google Play, there are third-party development of course. On the emulator it is possible, but these are terrible brakes, better device is usb + adb. - NewView pm

4 answers 4

Using OpenCV should of course be more successful. I experimented with AForge

loaded library

it turned out well too

application example

Here is the class of work with the library, in fact the use itself takes 2 lines, I confess, I took this part from the Internet, the rest was written by myself

 public class AforgeService { //Π½Π°ΠΉΠ΄Π΅Π½Π½Ρ‹Π΅ совпадСния private TemplateMatch[] _matchings; /// <summary> /// ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ Π½Π°ΠΉΠ΄Π΅Π½Π½Ρ‹Ρ… совпадСний /// </summary> public int CountMatchings { get => _matchings != null ? _matchings.Length : 0; } //ctor public AforgeService() { } /// <summary> /// Π‘ΠΎΠ΄Π΅Ρ€ΠΆΠΈΡ‚ Π»ΠΈ исходноС ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ прСдставлСный ΠΎΠ±Ρ€Π°Π·Π΅Ρ† /// </summary> /// <param name="pathOriginalImage">ΠΏΡƒΡ‚ΡŒ ΠΊ Ρ„Π°ΠΉΠ»Ρƒ исходного изобраТСния</param> /// <param name="pathSampleImage">ΠΏΡƒΡ‚ΡŒ ΠΊ Ρ„Π°ΠΉΠ»Ρƒ ΠΎΠ±Ρ€Π°Π·Ρ†Π°</param> /// <returns>true Ссли содСрТит</returns> public async Task<bool> IsContains(string pathOriginalImage, string pathSampleImage) { if (String.IsNullOrEmpty(pathOriginalImage)) throw new ArgumentNullException(nameof(pathOriginalImage)); if (String.IsNullOrEmpty(pathSampleImage)) throw new ArgumentNullException(nameof(pathSampleImage)); var sample = new Bitmap(pathSampleImage); var orig = new Bitmap(pathOriginalImage); //ΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡΡ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΎΠΉ ExhaustiveTemplateMatching tm = new ExhaustiveTemplateMatching(0.921f); _matchings = await Task.Run(() => tm.ProcessImage(orig, sample)); return _matchings.Any(); } /// <summary> /// ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΠΈ Π½Π°ΠΉΠ΄Π΅Π½Π½Ρ‹Ρ… мСст Π³Π΄Π΅ находится ΠΎΠ±Ρ€Π°Π·Π΅Ρ† /// </summary> /// <returns>коллСкция Π½Π°ΠΉΠ΄Π΅Π½Π½Ρ‹Ρ… мСст</returns> public List<FoundPlace> GetPlaces() { List<FoundPlace> result = new List<FoundPlace>(); if (CountMatchings == 0) return result; int id = 0; foreach (var match in _matchings) { FoundPlace place = new FoundPlace { Id = ++id, Similarity = match.Similarity, Top = match.Rectangle.Top, Left = match.Rectangle.Left, Height = match.Rectangle.Height, Width = match.Rectangle.Width }; result.Add(place); } return result; } } 

This class is for saving the found place.

 public class FoundPlace { public int Id { get; set; } public double Left { get; set; } public double Top { get; set; } public double Width { get; set; } public double Height { get; set; } public double Similarity { get; set; } } 

This is a view model class.

 public class MainViewModel : INotifyPropertyChanged, IDisposable { public event PropertyChangedEventHandler PropertyChanged; private readonly IMainWindow _mainWindow; private string _pathOriginalImage; //ctor public MainViewModel(IMainWindow mainWindow) { _mainWindow = mainWindow; } /// <summary> /// Π€Π»Π°Π³ запуска поиска, для Π²Ρ‹ΠΊΠ»./Π²ΠΊΠ». ΠΊΠ½ΠΎΠΏΠΎΠΊ /// </summary> private bool _IsSearching; public bool IsSearching { get => _IsSearching; set { _IsSearching = value; SelectSampleCommand.RaiseCanExecuteChanged(); SearchCommand.RaiseCanExecuteChanged(); } } /// <summary> /// Π˜ΡΡ…ΠΎΠ΄Π½ΠΎΠ΅ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ (ΠΏΠΎΠ»Π΅ ΠΈΠ³Ρ€Ρ‹) /// </summary> public string OriginalImage { get => @"~\..\Assets\Original.jpg"; } /// <summary> /// ΠžΠ±Ρ€Π°Π·Π΅Ρ† для поиска /// </summary> private string _SampleImage; public string SampleImage { get => _SampleImage; set { _SampleImage = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SampleImage))); SearchCommand.RaiseCanExecuteChanged(); } } /// <summary> /// ВСкстовоС сообщСниС ΠΎ процСссС /// </summary> private string _Message; public string Message { get => _Message; set { _Message = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Message))); } } /// <summary> /// Бписок Π½Π°ΠΉΠ΄Π΅Π½Π½Ρ‹Ρ… мСст для ListBox /// </summary> private List<FoundPlace> _Places; public List<FoundPlace> Places { get { return _Places; } set { _Places = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Places))); } } private FoundPlace _SelectedPlace; public FoundPlace SelectedPlace { get => _SelectedPlace; set { _SelectedPlace = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedPlace))); _mainWindow.DrawPlace(_SelectedPlace); } } /// <summary> /// Кнопка Π’Ρ‹Π±Ρ€Π°Ρ‚ΡŒ /// </summary> private RelayCommand _SelectSampleCommand; public RelayCommand SelectSampleCommand { get => _SelectSampleCommand = _SelectSampleCommand ?? new RelayCommand(OnSelectSample, CanSelectSample); } private bool CanSelectSample() { if (IsSearching) { return false; } return true; } private void OnSelectSample() { string file = _mainWindow.SelectSample(); if (String.IsNullOrEmpty(file)) return; SampleImage = file; } /// <summary> /// Кнопка Π˜ΡΠΊΠ°Ρ‚ΡŒ /// </summary> private RelayCommand _SearchCommand; public RelayCommand SearchCommand { get => _SearchCommand = _SearchCommand ?? new RelayCommand(OnSearch, CanSearch); } private bool CanSearch() { if (String.IsNullOrEmpty(SampleImage) || IsSearching) { return false; } return true; } private async void OnSearch() { Message = "Π–Π΄ΠΈΡ‚Π΅..."; IsSearching = true; AforgeService service = new AforgeService(); try { using (OverrideCursor cursor = OverrideCursor.GetWaitOverrideCursor()) { string pathOrigin = GetOriginalImage(); bool isContains = await service.IsContains(pathOrigin, SampleImage); if (isContains) { Places = service.GetPlaces(); } else { Places = new List<FoundPlace>(); } } } catch (Exception ex) { var message = $"Π’ΠΎΠ·Π½ΠΈΠΊΠ»Π° ошибка: {ex.Message}"; _mainWindow.ShowMessage(message, "Ошибка"); } finally { Message = $"НайдСно мСст: {service.CountMatchings}"; IsSearching = false; } } /// <summary> /// ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΠΏΡƒΡ‚ΠΈ ΠΊ ΠΎΡ€ΠΈΠ³ΠΈΠ½Π°Π»ΡŒΠ½ΠΎΠΌΡƒ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΡŽ (полю ΠΈΠ³Ρ€Ρ‹) /// </summary> /// <returns></returns> private string GetOriginalImage() { if (!String.IsNullOrEmpty(_pathOriginalImage) && File.Exists(_pathOriginalImage)) { return _pathOriginalImage; } _pathOriginalImage = Path.Combine(Path.GetTempPath(), "Original.jpg"); Uri imgUri = new Uri("pack://application:,,,/Assets/Original.jpg"); StreamResourceInfo imgStream = Application.GetResourceStream(imgUri); using (Stream imgs = imgStream.Stream) using (FileStream fs = File.Create(_pathOriginalImage)) { byte[] ar = new byte[imgs.Length]; imgs.Read(ar, 0, ar.Length); fs.Write(ar, 0, ar.Length); } return _pathOriginalImage; } /// <summary> /// IDisposable /// </summary> public void Dispose() { if (!String.IsNullOrEmpty(_pathOriginalImage) && File.Exists(_pathOriginalImage)) { File.Delete(_pathOriginalImage); } } } 

The whole example can be downloaded here.

  • OpenCV is learning as far as I know? Is it possible to train him so that he determines whether the buildings are in the inside of the fence or outside? - VikiMayson pm
  • @VikiMayson I have not worked with OpenCV , because, excuse me, I can not say anything intelligible. I just quickly sketched an example, because I was interested in your question. - Bulson
  • aforge see, too, has machine learning and neurons. On it there is nothing in my task do not tell? There are just moments when some objects overlap with others, and I definitely want to realize that it determines where objects are located, inside or outside the fence. Therefore, I want to teach. - VikiMayson
  • 2
    @VikiMayson, again I'm sorry, but I’m saying that in a hurry ... I myself hope to find the time and read the docks, experiment :) - Bulson
  • one
    At the end of my answer there is a link to an example that can be downloaded. In the project folder you will find the bin folder in it is the Debug folder. Copy it with all the files and run the exe file, it should work (it is important that all files are in the same folder). Only this is an example, not a complete program. It is not possible to replace the image by the cat. You need to search. - Bulson pm

I think you have enough functionality implemented in OpenCV

OpenCV (English Open Source Computer Vision Library, open source computer vision library) is a library of computer vision, image processing and general-purpose numerical algorithms with open source.

(c) Wikipedia.

Here are some good lessons about it, but what you can come in handy in theory.

    There is a large, complex and popular area of ​​technology called image recognition. For the most part deep neural networks are used there, but not only. And it is unlikely that such complexity is necessary in your case (although it can inspire the correct vector of further actions).

    A simple way is to break the playing field into parts (it seems that this game is especially important in this game) and check each part for similarities with known objects. If items can be in random places, and not just on a given grid, then a more advanced analysis is needed: you can first check on the grid, then on the same grid with a half shift (or even a third and two thirds). You can also scale it, take a certain hash from a part of the image ...

    By the way, if you can’t achieve 99% accuracy (which is possible in principle, because all objects will be static and not rotated under different lighting, as in the real world), then you can compensate for the accuracy by the reasonableness of clicks: to save positions that have been unsuccessfully clicked in the next times do not blunt, do not waste time Then the main thing is that the search algorithm should produce as few false positives as possible, and false positives will be quickly cut off in practice.

    Useful links:

      If you need to search for an image of a fragment of this image, and not something remotely resembling a fragment, there is nothing better than the correlation method. Fast and reliable. And no recognition is needed.