A bit late answer, but hopefully useful.
Cutting short, yes, there is a way. However, I couldn't find, how to do it without callout to Reports REST API Description.
String reportId = '00O63000001NtWU';
Http http = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm() + '/services/data/v51.0/analytics/reports/' + reportId + '/describe');
req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId());
req.setMethod('GET');
HttpResponse res = http.send(req);
Map<String, Object> resBody = (Map<String, Object>) JSON.deserializeUntyped(res.getBody());
Map<String, Object> reportExtendedMetadata = (Map<String, Object>) resBody.get('reportExtendedMetadata');
Map<String, Object> detailColumnInfo = (Map<String, Object>) reportExtendedMetadata.get('detailColumnInfo');
for (String key : detailColumnInfo.keySet()) {
Map<String, Object> tmp = (Map<String, Object>) detailColumnInfo.get(key);
System.debug(key + ' ' + (String) tmp.get('entityColumnName')); // OPPORTUNITY_NAME Opportunity.Name
}
I have also tried to retrieve reportExtendedMetadata without callout, but it has less information in detailColumnInfo (the core thing it has NO entityColumnName info):
String reportId = '00O63000001NtWU';
Reports.reportResults body = Reports.ReportManager.runReport(reportId, true);
Reports.ReportExtendedMetadata reportExtendedMetadata = body.getReportExtendedMetadata();
Map<String, Reports.DetailColumn> detailColumnInfo = reportExtendedMetadata.getDetailColumnInfo();
for (String key : detailColumnInfo.keySet()) {
System.debug(detailColumnInfo.get(key).getName()); // no information about entityColumnName
}