Author: Xing Anguo


Derived from:
I used Python to sneak up on my girlfriend behind her back



The target scene

Sometimes my girlfriend plays outside alone and asks her where she is, but won’t tell me. But what if you want to know where your girlfriend is?In fact, you can do this to your girlfriend, pretend that you are bored at home, you can help her edit the picture, ask her wechat to send you the original picture, after getting the “wechat original picture”, you can use Python to quickly get the specific location of your girlfriend.

The preparatory work

First, install a library that recognizes image metadata in your virtual environment.

pip3 install exifreadCopy the code

Then, enter autonavi open platform, apply for a Web service application, and obtain a “Key” for reverse geocoding API.

Write a script

The whole operation is divided into three steps, namely, obtaining the longitude and latitude of the image, correcting the longitude and latitude data, and calling Autonavi inverse geocoding API to obtain the specific location.

Step 1: Get the longitude and latitude of the image.

Using the Exifread library, you can directly read the image file and obtain the metadata of the image, including the longitude, latitude, north and south latitude, east and west longitude and the time when the image was taken.

Use exifread to retrieve image metadata
img_exif = exifread.process_file(open(self.img_path, 'rb'))
​
Properties can be read
if img_exif:
     # number of latitude
     latitude_gps = img_exif['GPS GPSLatitude']
​
     # N,S in north and south latitudes
     latitude_direction = img_exif['GPS GPSLatitudeRef']
​
     # the degree
     longitude_gps = img_exif['GPS GPSLongitude']
​
     # E,W east-west longitude
     longitude_direction = img_exif['GPS GPSLongitudeRef']
​
     # Shooting time
     take_time = img_exif['EXIF DateTimeOriginal']Copy the code

If metadata exists, then determine if the shooting time is reasonable. If it’s not today, I’m sorry to inform you that your girlfriend is lying to you.

def judge_time_met(self, take_time):
    """Param take_time: :return:"""
    # Shooting time
    format_time = str(take_time).split("")[0].replace(":"."-")
​
    # Date of the day
    today = str(datetime.date.today())
​
    if format_time == today:
        return True
    else:
        return False
​
if is_lie:
        print('SORRY to inform you that your girlfriend is lying!! ')
        returnCopy the code

If she is not lying, go to step 2.

Because there is some error in longitude, latitude and coordinates of Amap obtained by GPS, the coordinates need to be converted to “Mars coordinate system”.

X_pi = 3.14159265358979324 * 3000.0/180.0 PI = 3.1415926535897932384626# PI.A = 6378245.0# semi-major axisEe = 0.00669342162296594323# flat rate
​
def wgs84togcj02(lng, lat):
    """WGS84 to GCJ02(Mars coordinates) : Param LNG: Longitude of WGS84 coordinates: Param Lat: latitude of WGS84 coordinates :return:"""
    if out_of_china(lng, lat):  # Determine if it is in the country
        returnLNG, LAT DLAT = TransformLAT (LNG-105.0, LAT-35.0) DLNG = TransformLLNG (LNG-105.0, LAT-35.0) Lat-35.0) radlat = Lat / 180.0 * PI magic = math.sin(radlat) magic = 1 - EE * magic * magic sqrtMagic = Math.sqrt (magic) dlAT = (dlAT * 180.0)/((a * (1-EE))/(Magic * SQrtMagic) * PI) DLNG = (DLNG * 180.0)/(a / sqrtmagic * math.cos(radlat) * pi) mglat = lat + dlat mglng = lng + dlngreturn [mglng, mglat]Copy the code

In addition, the longitude and latitude parameters in the interface can identify only six decimal places. You need to perform certain data processing for degrees, minutes, and seconds in the longitude and latitude before rounding them off.

def __format_lati_long_data(self, data):
    ""Param data: original latitude and longitude values :return:""
    Delete the left and right parentheses and Spaces
    data_list_tmp = str(data).replace('['.' ').replace('] '.' ').split(', ')
    data_list = [data.strip() for data in data_list_tmp]
​
    # Replace the value of seconds
    data_tmp = data_list[-1].split('/')
​
    The value of # s
    data_sec = int(data_tmp[0]) / int(data_tmp[1]) / 3600
​
    # Replace the value of the score
    data_tmp = data_list[-2]
​
    The value of # points
    data_minute = int(data_tmp) / 60
​
    The value of the # degrees
    data_degree = int(data_list[0])
​
    # Because the Autonavi API can only recognize 6 decimal places
    # needs to be converted to a floating point number and retained as a 6-digit decimal
    result = "%.6f" % (data_degree + data_minute + data_sec)
    return float(result)Copy the code

Step 3: Call Autonavi’s anti-geocoding API, pass in the application Key, and get the detailed address of your girlfriend.

def __get_address(self, location):
    ""Param location: latitude and longitude value :return:""
    resp = requests.get(self.url_get_position.format(self.api_key, location))
​
    location_data = json.loads(resp.text)
​
    address = location_data.get('regeocode').get('formatted_address')
​
    return addressCopy the code

The complete code

main.py

import os
import exifread
from decimal import Decimal
from position_utils import *
import requests
import json
import datetime
​
​
# pip3 install exifread
​
​
class Location(object):
​
    def __init__(self, image_path):
        self.img_path = image_path
​
        self.api_key = "The AK you applied for"
​
        self.url_get_position = 'https://restapi.amap.com/v3/geocode/regeo?key={}&location={}'
​
    def run(self):
        coordinate = self.__get_image_ability()
​
        print(f'Get longitude and latitude is {coordinate}'.)
​
        if not coordinate:
            returnObtain the detailed address according to longitude and latitude
        address = self.__get_address(coordinate)
​
        # Check coordinate values
        # https://lbs.amap.com/console/show/picker
        print(f'Your girlfriend is at :{address}')
​
    def __get_address(self, location):
        ""Param location: latitude and longitude value :return:""
        resp = requests.get(self.url_get_position.format(self.api_key, location))
​
        location_data = json.loads(resp.text)
​
        address = location_data.get('regeocode').get('formatted_address')
​
        return address
​
    def __format_lati_long_data(self, data):
        ""Param data: original latitude and longitude values :return:""
        Delete the left and right parentheses and Spaces
        data_list_tmp = str(data).replace('['.' ').replace('] '.' ').split(', ')
        data_list = [data.strip() for data in data_list_tmp]
​
        # Replace the value of seconds
        data_tmp = data_list[-1].split('/')
​
        The value of # s
        data_sec = int(data_tmp[0]) / int(data_tmp[1]) / 3600
​
        # Replace the value of the score
        data_tmp = data_list[-2]
​
        The value of # points
        data_minute = int(data_tmp) / 60
​
        The value of the # degrees
        data_degree = int(data_list[0])
​
        # Because the Autonavi API can only recognize 6 decimal places
        # needs to be converted to a floating point number and retained as a 6-digit decimal
        result = "%.6f" % (data_degree + data_minute + data_sec)
        return float(result)
​
    def __get_image_ability(self):
        """Param picture_name: :return:"""# Use the exifread library to read the attributes of the image
        img_exif = exifread.process_file(open(self.img_path, 'rb'))
​
        Properties can be read
        if img_exif:
            # number of latitude
            latitude_gps = img_exif['GPS GPSLatitude']
​
            # N,S in north and south latitudes
            latitude_direction = img_exif['GPS GPSLatitudeRef']
​
            # the degree
            longitude_gps = img_exif['GPS GPSLongitude']
​
            # E,W east-west longitude
            longitude_direction = img_exif['GPS GPSLongitudeRef']
​
            # Shooting time
            take_time = img_exif['EXIF DateTimeOriginal']
​
            is_lie = self.judge_time_met(take_time)
​
            if is_lie:
                print('SORRY to inform you that your girlfriend is lying!! ')
                return# Latitude, longitude, shooting time
            if latitude_gps and longitude_gps and take_time:
​
                The original values of latitude and longitude are further processed
                latitude = self.__format_lati_long_data(latitude_gps)
                longitude = self.__format_lati_long_data(longitude_gps)
​
                # print(f'{longitude},{latitude}')# Note: Since the coordinates obtained by GPS are not accurately inverse encoded on mainstream maps such as Autonavi in China, they need to be converted to Mars coordinate system
                location = wgs84togcj02(longitude, latitude)
​
                return f'{location[0]},{location[1]}'
            else:
                print(f'Incomplete image data properties obtained')
                return ' '
        else:
            print('Sorry, the image is not the original image, can't get image properties. ')
            return ' '
​
    def judge_time_met(self, take_time):
        """Param take_time: :return:"""
        # Shooting time
        format_time = str(take_time).split("")[0].replace(":"."-")
​
        # Date of the day
        today = str(datetime.date.today())
​
        if format_time == today:
            return False
        else:
            return True
​
​
if __name__ == '__main__':
    # My girlfriend sent me the picture [original picture]
    location = Location('./picture/11441566648796_.pic_hd.jpg')
​
    # Find your girlfriend's location
    location.run()Copy the code

position_utils.py

Import json import math x_pi = 3.14159265358979324 * 3000.0/180.0 PI = 3.1415926535897932384626# PI.A = 6378245.0# semi-major axisEe = 0.00669342162296594323# flat rate
​
​
def wgs84togcj02(lng, lat):
    """WGS84 to GCJ02(Mars coordinates) : Param LNG: Longitude of WGS84 coordinates: Param Lat: latitude of WGS84 coordinates :return:"""
    if out_of_china(lng, lat):  # Determine if it is in the country
        returnLNG, LAT DLAT = TransformLAT (LNG-105.0, LAT-35.0) DLNG = TransformLLNG (LNG-105.0, LAT-35.0) Lat-35.0) radlat = Lat / 180.0 * PI magic = math.sin(radlat) magic = 1 - EE * magic * magic sqrtMagic = Math.sqrt (magic) dlAT = (dlAT * 180.0)/((a * (1-EE))/(Magic * SQrtMagic) * PI) DLNG = (DLNG * 180.0)/(a / sqrtmagic * math.cos(radlat) * pi) mglat = lat + dlat mglng = lng + dlngreturn [mglng, mglat]
​
​
def gcj02towgs84(lng, lat):
    """GCJ02(Mars coordinates) to GPS84: Param LNG: Longitude of Mars coordinates: Param Lat: Latitude of Mars coordinates :return:"""
    if out_of_china(lng, lat):
        returnLNG, LAT DLAT = TransformLAT (LNG-105.0, LAT-35.0) DLNG = TransformLLNG (LNG-105.0, LAT-35.0) Lat-35.0) radlat = Lat / 180.0 * PI magic = math.sin(radlat) magic = 1 - EE * magic * magic sqrtMagic = Math.sqrt (magic) dlAT = (dlAT * 180.0)/((a * (1-EE))/(Magic * SQrtMagic) * PI) DLNG = (DLNG * 180.0)/(a / sqrtmagic * math.cos(radlat) * pi) mglat = lat + dlat mglng = lng + dlngreturn[lng * 2 - mglng, lat * 2 - mglat] def transformlat(lng, lat): Ret = -100.0 + 2.0 * LNG + 3.0 * Lat + 0.2 * Lat * Lat + \ 0.1 * LNG * lat + 0.2 * math.sqRT (math.fabs(LNG)) RET += (20.0 * math.sin(6.0 * LNG * PI) + 20.0 * math.sin(2.0 * LNG * PI)) * 2.0/3.0 ret += (20.0 * Math. sin(Lat * PI) + 40.0 * math.sin(lat / 3.0 * PI)) * 2.0/3.0 ret += (160.0 * math.sin(lat / 12.0 * PI) + 320 * math.sin(lat * PI / 30.0)) * 2.0/3.0returnret def transformlng(lng, lat): Ret = 300.0 + LNG + 2.0 * Lat + 0.1 * LNG * LNG + \ 0.1 * LNG * Lat + 0.1 * math.sqRT (math.fabs(LNG)) RET += (20.0 * Math. sin(6.0 * LNG * PI) + 20.0 * math.sin(2.0 * LNG * PI)) * 2.0/3.0 ret += (20.0 * Math. sin(LNG * PI) + 40.0 * Math. sin(LNG / 3.0 * PI)) * 2.0/3.0 ret += (150.0 * math.sin(LNG / 12.0 * PI) + 300.0 * math.sin(LNG / 30.0 * PI)) * 2.0/3.0return ret
​
​
def out_of_china(lng, lat):
    """Check whether it is in China or not :param LNG: : Param lat: :return:"""
    ifLNG < 72.004 or LNG > 137.8347:return True
    ifLat < 0.8293 or LAT > 55.8271:return True
    return FalseCopy the code

Results the conclusion

Make sure the picture is the original one and you can quickly tell if your girlfriend is lying. If she is not lying, return to her specific location.

PS: All of this has a premise, that you have to have a girlfriend first!