<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def Get3DData(self, datapath, qt_app=None, dataplus_format=True, gui=False, start=0, stop=None, step=1, convert_to_gray=True, series_number=None, use_economic_dtype=True, dicom_expected=None, **kwargs):
 """Returns 3D data and its metadata. # NOTE(:param qt_app:) If it is set to None (as default) all dialogs for series selection are performed in terminal. If qt_app is set to QtGui.QApplication() dialogs are in Qt. :param datapath: directory with input data :param qt_app: Dialog destination. If None (default) -> terminal, if 'QtGui.QApplication()' -> Qt :param dataplus_format: New data format. Metadata and data are returned in one structure. :param gui: True if 'QtGui.QApplication()' instead of terminal should be used :param int start: used for DicomReader, defines where 3D data reading should start :param int stop: used for DicomReader, defines where 3D data reading should stop :param int step: used for DicomReader, defines step for 3D data reading :param bool convert_to_gray: if True -> RGB is converted to gray :param int series_number: used in DicomReader, essential in metadata :param use_economic_dtype: if True, casts 3D data array to less space consuming dtype :param dicom_expected: set true if it is known that data is in dicom format. Set False to suppress dicom warnings. :return: tuple (data3d, metadata) """

        self.orig_datapath = datapath
        datapath = os.path.expanduser(datapath)

        if series_number is not None and type(series_number) != int:
            series_number = int(series_number)

        if not os.path.exists(datapath):
            logger.error("Path '" + datapath + "' does not exist")
            return
        if qt_app is None and gui is True:
            from PyQt4.QtGui import QApplication
            qt_app = QApplication(sys.argv)

        if type(datapath) is not str:
            datapath = str(datapath)
        datapath = os.path.normpath(datapath)

        self.start = start
        self.stop = stop
        self.step = step
        self.convert_to_gray = convert_to_gray
        self.series_number = series_number
        self.kwargs = kwargs
        self.qt_app = qt_app
        self.gui = gui

        if os.path.isfile(datapath):
            logger.debug('file read recognized')
            data3d, metadata = self.__ReadFromFile(datapath)

        elif os.path.exists(datapath):
            logger.debug('directory read recognized')
            data3d, metadata = self.__ReadFromDirectory(datapath=datapath, dicom_expected=dicom_expected)
            # datapath, start, stop, step, gui=gui, **kwargs)
        else:
            logger.error('Data path {} not found'.format(datapath))

        if convert_to_gray:
            if len(data3d.shape) > 3:
                # TODO: implement better rgb2gray
                data3d = data3d[:, :, :, 0]
        if use_economic_dtype:
            data3d = self.__use_economic_dtype(data3d)

        if dataplus_format:
            logger.debug('dataplus format')
            # metadata = {'voxelsize_mm': [1, 1, 1]}
            datap = metadata
            datap['data3d'] = data3d
            logger.debug('datap keys () : ' + str(datap.keys()))
            return datap
        else:
            return data3d, metadata